Spring解决cross domain

本文详细解析了Spring MVC中实现跨域请求的方法,包括针对Spring4和Spring3的不同配置方式,并介绍了如何通过预检请求解决跨域问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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实现跨域,原有实现以及客户端代码不需要任何改动。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值