springboot学习(三十四) springboot+stomp+sockJs在spring5.3以上报跨域问题的处理

将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,问题解决了

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值