Spring解决cross domain

    xiaoxiao2021-03-25  47

    Spring4:

    在requestMapping中使用注解。 @CrossOrigin(origins = “http://localhost:9000”)全局实现 .定义类继承WebMvcConfigurerAdapter public class CorsConfigurerAdapter extends WebMvcConfigurerAdapter{ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/*").allowedOrigins("*"); } }

    将该类注入到容器中:

    <bean class="com.tmall.wireless.angel.web.config.CorsConfigurerAdapter"></bean>

    Spring3旧版本:

    在org.springframework.web.servlet.DispatcherServlet.doDispatch中会根据根据request来获取HandlerExecutionChain,SpringMVC在获取常规的处理器后会检查是否为跨域请求,如果是则替换原有的实例。

    @Override public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Object handler = getHandlerInternal(request); if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); if (CorsUtils.isCorsRequest(request)) { CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; }

    检查的方法也很简单,即检查请求头中是否有origin字段

    public static boolean isCorsRequest(HttpServletRequest request) { return (request.getHeader(HttpHeaders.ORIGIN) != null); }

    请求接着会交由 HttpRequestHandlerAdapter.handle来处理,根据handle不同,处理不同的逻辑。前面根据请求头判断是一个跨域请求,获取到的Handler为PreFlightHandler,其实现为:

    @Override public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws IOException { corsProcessor.processRequest(this.config, request, response); }

    继续跟进

    @Override public boolean processRequest(CorsConfiguration config, HttpServletRequest request, HttpServletResponse response) throws IOException { if (!CorsUtils.isCorsRequest(request)) { return true; } ServletServerHttpResponse serverResponse = new ServletServerHttpResponse(response); ServletServerHttpRequest serverRequest = new ServletServerHttpRequest(request); if (WebUtils.isSameOrigin(serverRequest)) { logger.debug("Skip CORS processing, request is a same-origin one"); return true; } if (responseHasCors(serverResponse)) { logger.debug("Skip CORS processing, response already contains \"Access-Control-Allow-Origin\" header"); return true; } boolean preFlightRequest = CorsUtils.isPreFlightRequest(request); if (config == null) { if (preFlightRequest) { rejectRequest(serverResponse); return false; } else { return true; } } return handleInternal(serverRequest, serverResponse, config, preFlightRequest); }

    此方法首先会检查是否为跨域请求,如果不是则直接返回,接着检查是否同一个域下,或者response头里是否具有Access-Control-Allow-Origin字段或者request里是否具有Access-Control-Request-Method。如果满足判断条件,则拒绝这个请求。 由此我们知道,可以通过在检查之前设置response的Access-Control-Allow-Origin头来通过检查。我们在拦截器的preHandle的处理。加入如下代码:

    response.setHeader("Access-Control-Allow-Origin", "*");

    此时浏览器中OPTIONS请求返回200。但是依然报错:

    Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.

    我们注意到:在request的请求头里有Access-Control-Request-Headers:accept, content-type,但是这个请求头的中没有,此时浏览器没有据需发送请求。尝试在response中加入:

    response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");

    执行成功:Object {userId: 123, userName: “adminUpdate-wangdachui”}。

    至此:我们通过分析原理使SpringMVC实现跨域,原有实现以及客户端代码不需要任何改动。

    转载请注明原文地址: https://ju.6miu.com/read-50270.html

    最新回复(0)