springboot2.4.x websocket跨域问题
1,springboot升级版本以后websocket连接出现以下错误
java.lang.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.
2,SpringBoot 2.4.0版本后解决跨域问题(较之前的版本有些变化)
请注意注释代码的替换:
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addCorsMappings( CorsRegistry registry) { registry.addMapping("/**")//允许请求路径 //.allowedOrigins("*")//表示允许所有网址发起跨域请求 .allowedOriginPatterns("*")//表示允许所有网址发起跨域请求 .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")//表示允许跨域请求的方法 .allowedMethods("*") .maxAge(3600)//表示在3600秒内不需要再发送预校验请求 .allowCredentials(true);//允许客户端携带验证信息,即允许携带cookie } }
3,SpringBoot 2.4.0对应的websocket配置
请注意,2.4.X的SpringBoot对应的websocket跨域配置并没有setAllowedOriginPatterns这个方法,建议升级更高版本springboot,笔者亲测springboot2.5.6版本可以用
猜测:可能是SpringBoot2.4.X对springweb跨域底层做了修改,但是这个版本对应的websocket(5.3.1~5.3.9)并没有对此做出适配,建议使用SpringBoot更高版或降低版本。
package com.zl.config; import com.zl.websocket.Operation; import com.zl.websocket.message.MessageProcessor; import com.zl.websocket.message.StompMessageConsumer; import com.zl.websocket.message.StompMessagePusher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.simp.SimpMessageHeaderAccessor; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.messaging.simp.config.ChannelRegistration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.messaging.simp.stomp.StompHeaderAccessor; import org.springframework.messaging.support.ChannelInterceptor; import org.springframework.messaging.support.MessageHeaderAccessor; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; /** * @Author zl * @Description * @Date 2022/8/22 21:40 */ @Configuration @EnableWebSocketMessageBroker public class StompMessageConfig implements WebSocketMessageBrokerConfigurer { //protected static Logger LOGGER = LoggerFactory.getLogger(com.zn.stomp.configuration.StompMessageConfig.class); @Autowired(required = false) private Operation operation; @Override public void registerStompEndpoints(StompEndpointRegistry registry) { String endpointName = "endpoint"; registry.addEndpoint(endpointName) //.setAllowedOrigins("*") .setAllowedOriginPatterns("*") .withSockJS(); } @Override public void configureMessageBroker(MessageBrokerRegistry registry) { String topicFixed = "/topic"; String appFixed = "/app"; String userFixed = "/user"; registry.enableSimpleBroker(topicFixed, userFixed); registry.setApplicationDestinationPrefixes(appFixed); registry.setUserDestinationPrefix(userFixed); } @Override public void configureClientInboundChannel(ChannelRegistration registration) { registration.interceptors(new ChannelInterceptor() { @Override public Message<?> preSend(Message<?> message, MessageChannel channel) { StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class); assert accessor != null; Object simpSessionId = message.getHeaders().get(SimpMessageHeaderAccessor.SESSION_ID_HEADER); if (simpSessionId instanceof String) { if (operation == null) { // LOGGER.error("Operation not found instance!!!"); return message; } operation.operation(accessor.getCommand(), (String) simpSessionId, message.getHeaders()); } return message; } }); } @Override public void configureClientOutboundChannel(ChannelRegistration registration) { if (operation == null) { return; } operation.clientOutboundChannel(registration); } @Bean public StompMessagePusher stompMessagePusher(SimpMessagingTemplate messagingTemplate){ //LOGGER.info("spring auto create StompMessagePusher component."); return new StompMessagePusher(messagingTemplate); } @Bean @ConditionalOnBean(MessageProcessor.class) public StompMessageConsumer stompMessageConsumer(MessageProcessor messageProcessor){ //LOGGER.info("spring auto create StompMessageConsumer component."); return new StompMessageConsumer(messageProcessor); } }
心有所想,必有回响