在nginx跨域请求cors配置如下:
location / { add_header 'Access-Control-Allow-Origin' 'https://api.xxxx.com'; add_header "Access-Control-Allow-Credentials" "true"; add_header "Access-Control-Allow-Headers" "x-requested-with,content-type"; proxy_pass http://localhost:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
主要是添加了三个用于控制CORS的头信息:
这个配置也可以在spring mvc里配置。
问题:
配置好后,异步跨域请求成功。
当发起post请求,请求的数据是放在request body里,请求的Content-Type为application/json。Spring MVC需要使用@RequestBody来接收数据。
这是一次非简单的请求,浏览器会发起一次Options的预请求。发起Options请求报403错误:
Failed to load https://api.xxxx.com/auth.json: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://other.xxxx.com' is therefore not allowed access. The response had HTTP status code 403.
解决方法
原以为是自己的配置有误,但找了很多资料可以确定配置是没有问题。后来debug跟踪Spring MVC DispatcherServlet的调用,发现在DispacerServlet是因为没有找都到执行Options请求的方法。
在做跨域请求时,配置好CORS相关头信息后,以为就可以了,这很容易忽略在Spring MVC添加对Options请求的处理。
解决方法有两种:
拦截器示例:
public class CrosDomainAllowInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if(request.getMethod().equals(RequestMethod.OPTIONS.name())) { response.setStatus(HttpStatus.OK.value()); return false; } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
@RequestMapping示例
@RequestMapping(value = "/*",method = RequestMethod.OPTIONS) public ResponseEntity handleOptions(){ return ResponseEntity.noContent(); }
快速登录,邮箱登录或 注册