赞
踩
将springboot升级到2.4.0后websocket报跨域问题,报错如下:
When allowCredentials is true, allowedOrigins cannot contain the special value "*"since that cannot be set on the “Access-Control-Allow-Origin” response header. To allow credentials to a set of origins, list them explicitly or consider using “allowedOriginPatterns” instead.
经过跟代码发现是spring5.3以上的一个函数:
/** * Validate that when {@link #setAllowCredentials allowCredentials} is true, * {@link #setAllowedOrigins allowedOrigins} does not contain the special * value {@code "*"} since in that case the "Access-Control-Allow-Origin" * cannot be set to {@code "*"}. * @throws IllegalArgumentException if the validation fails * @since 5.3 */ public void validateAllowCredentials() { if (this.allowCredentials == Boolean.TRUE && this.allowedOrigins != null && this.allowedOrigins.contains(ALL)) { throw new IllegalArgumentException( "When allowCredentials is true, allowedOrigins cannot contain the special value \"*\"" + "since that cannot be set on the \"Access-Control-Allow-Origin\" response header. " + "To allow credentials to a set of origins, list them explicitly " + "or consider using \"allowedOriginPatterns\" instead."); } }
解决办法:
1 继承SimpleUrlHandlerMapping重写getConfiguration函数
package com.iscas.base.biz.config.stomp; import org.springframework.context.Lifecycle; import org.springframework.context.SmartLifecycle; import org.springframework.web.context.ServletContextAware; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.servlet.HandlerExecutionChain; import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; import org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.Arrays; /** * 升级springboot到2.4.0后websocket出现跨域问题处理,重写MyWebSocketHandlerMapping * * @author zhuquanwen * @vesion 1.0 * @date 2020/11/25 13:59 * @since jdk1.8 */ public class MyWebSocketHandlerMapping extends SimpleUrlHandlerMapping implements SmartLifecycle { private volatile boolean running; @Override protected void initServletContext(ServletContext servletContext) { for (Object handler : getUrlMap().values()) { if (handler instanceof ServletContextAware) { ((ServletContextAware) handler).setServletContext(servletContext); } } } @Override public void start() { if (!isRunning()) { this.running = true; for (Object handler : getUrlMap().values()) { if (handler instanceof Lifecycle) { ((Lifecycle) handler).start(); } } } } @Override public void stop() { if (isRunning()) { this.running = false; for (Object handler : getUrlMap().values()) { if (handler instanceof Lifecycle) { ((Lifecycle) handler).stop(); } } } } @Override public boolean isRunning() { return this.running; } @Override public CorsConfiguration getCorsConfiguration(Object handler, HttpServletRequest request) { Object resolvedHandler = handler; if (handler instanceof HandlerExecutionChain) { resolvedHandler = ((HandlerExecutionChain) handler).getHandler(); } if (resolvedHandler instanceof CorsConfigurationSource) { // if (!this.suppressCors && (request.getHeader(HttpHeaders.ORIGIN) != null)) { // } // return null; if (resolvedHandler instanceof SockJsHttpRequestHandler) { String origin = request.getHeader("Origin"); CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(new ArrayList<>(Arrays.asList(origin))); config.addAllowedMethod("*"); config.setAllowCredentials(true); config.setMaxAge(365 * 24 * 3600L); config.addAllowedHeader("*"); return config; } else { return ((CorsConfigurationSource) resolvedHandler).getCorsConfiguration(request); } } return null; } }
2 继承MyWebMvcStompEndpointRegistry重写getHandlerMapping函数
package com.iscas.base.biz.config.stomp; import cn.hutool.core.util.ReflectUtil; import org.springframework.scheduling.TaskScheduler; import org.springframework.util.MultiValueMap; import org.springframework.web.HttpRequestHandler; import org.springframework.web.servlet.handler.AbstractHandlerMapping; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.config.annotation.WebMvcStompEndpointRegistry; import org.springframework.web.socket.config.annotation.WebMvcStompWebSocketEndpointRegistration; import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration; import org.springframework.web.util.UrlPathHelper; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * 升级springboot到2.4.0后websocket出现跨域问题处理,重写WebMvcStompEndpointRegistry * * @author zhuquanwen * @vesion 1.0 * @date 2020/11/25 13:44 * @since jdk1.8 */ public class MyWebMvcStompEndpointRegistry extends WebMvcStompEndpointRegistry { public MyWebMvcStompEndpointRegistry(WebSocketHandler webSocketHandler, WebSocketTransportRegistration transportRegistration, TaskScheduler defaultSockJsTaskScheduler) { super(webSocketHandler, transportRegistration, defaultSockJsTaskScheduler); } public AbstractHandlerMapping getHandlerMapping() { Map<String, Object> urlMap = new LinkedHashMap<>(); List<WebMvcStompWebSocketEndpointRegistration> registrations = null; try { registrations = (List<WebMvcStompWebSocketEndpointRegistration>) ReflectUtil.getFieldValue(this, "registrations"); } catch (Exception e) { e.printStackTrace(); } for (WebMvcStompWebSocketEndpointRegistration registration : registrations) { MultiValueMap<HttpRequestHandler, String> mappings = registration.getMappings(); mappings.forEach((httpHandler, patterns) -> { for (String pattern : patterns) { urlMap.put(pattern, httpHandler); } }); } MyWebSocketHandlerMapping hm = new MyWebSocketHandlerMapping(); hm.setUrlMap(urlMap); int order = 1; try { order = (int) ReflectUtil.getFieldValue(this, "order"); } catch (Exception e) { e.printStackTrace(); } hm.setOrder(order); UrlPathHelper urlPathHelper = null; try { urlPathHelper = (UrlPathHelper) ReflectUtil.getFieldValue(this, "urlPathHelper"); } catch (Exception e) { e.printStackTrace(); } if (urlPathHelper != null) { hm.setUrlPathHelper(urlPathHelper); } return hm; } }
3 继承DelegatingWebSocketMessageBrokerConfiguration重写stompWebSocketHandlerMapping函数
package com.iscas.base.biz.config.stomp; import cn.hutool.core.util.ReflectUtil; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.config.annotation.DelegatingWebSocketMessageBrokerConfiguration; /** * 升级springboot到2.4.0后websocket出现跨域问题处理,重写DelegatingWebSocketMessageBrokerConfiguration * * @author zhuquanwen * @vesion 1.0 * @date 2020/11/25 13:12 * @since jdk1.8 */ @Configuration //@Primary //@Order(Ordered.HIGHEST_PRECEDENCE) public class MyDelegatingWebSocketMessageBrokerConfiguration extends DelegatingWebSocketMessageBrokerConfiguration { // @Bean // @Primary public HandlerMapping stompWebSocketHandlerMapping() { WebSocketHandler handler = decorateWebSocketHandler(subProtocolWebSocketHandler()); MyWebMvcStompEndpointRegistry registry = new MyWebMvcStompEndpointRegistry( handler, getTransportRegistration(), messageBrokerTaskScheduler()); ApplicationContext applicationContext = getApplicationContext(); if (applicationContext != null) { try { ReflectUtil.setFieldValue(this, "applicationContext", applicationContext); } catch (Exception e) { e.printStackTrace(); } // registry.setApplicationContext(applicationContext); } registerStompEndpoints(registry); return registry.getHandlerMapping(); } }
OK,问题解决了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。