怎样避免跨域发出OPTIONS请求?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了怎样避免跨域发出OPTIONS请求?相关的知识,希望对你有一定的参考价值。

参考技术A 我们在做移动开发的时候,往往在服务器中加入Access-Control-Allow-Origin,用来跨域,虽然这是最简单的跨域方案了,但是有一个问题,就是每一次正式请求的前面总是会带上一次OPTIONS请求,一些程序员往往一头雾水。

浏览器在处理跨域请求之前,会先对跨域请求做一个分析,将跨域请求分为2种:简单请求,和非简单请求。

具备以下特征的是简单请求:

凡是超出这些限制的请求一律被浏览器视为复杂请求,如果想跨域,浏览器会发送一个OPTIONS请求,跟服务器一探究竟。

如果服务器返回的数据让浏览器很满意,那么浏览器才会发出正式请求。

因为OPTIONS请求也是占带宽和时间的,从上图也可以看到,每个请求都带一个OPTIONS,非常难受。怎么避免?

axios的默认请求内容类型是application/json,这就倒霉催的了,只能是修改成application/x-www-form-urlencoded。相应的,post数据的时候,要用qs库。具体做法去搜索吧。

你肯定是往headers里放东西了。别放就行了。

这下子前端是没有好办法了,只能从后端想办法了,就是使用Access-Control-Max-Age。

这需要后端同学配合,在设置OPTIONS跨域响应headers的时候,添加 Access-Control-Max-Age ,这个参数的意思是把 OPTIONS 响应缓存起来,在指定的时间内,不会再次发起 OPTIONS 预请求,这样只有在第一次请求的时候会有 OPTIONS ,之后浏览器会从缓存里读取响应,也就不会再发送OPTIONS请求了。比如:

注意,后端只需要处理OPTIONS请求,不要改正常的GET、POST请求。

使用 Spring MVC 4 处理跨域预检 AJAX OPTIONS 请求

【中文标题】使用 Spring MVC 4 处理跨域预检 AJAX OPTIONS 请求【英文标题】:Handling cross domain preflight AJAX OPTIONS requests with Spring MVC 4 【发布时间】:2015-08-12 11:59:40 【问题描述】:

这可能是一个简单的答案,但我似乎无法让它发挥作用。在跨域、预检 AJAX 请求中,客户端首先发出一个 OPTIONS 请求,然后返回一组标头以确定远程服务器接受的内容。

现在,对于我创建的每个 Spring 控制器 POST 接口,我还必须创建一个 OPTIONS 接口,如下所示:

 @RequestMapping(method = RequestMethod.OPTIONS, value = "/addWebService")
    public ResponseEntity addWebServiceOptions() 
        return new ResponseEntity(HttpStatus.NO_CONTENT);
    

@RequestMapping(method = RequestMethod.POST, value = "/addWebService")
    public AjaxResponse<WebService> addWebService(Principal principal, @RequestBody WebService webService) throws UserServiceException  ... 

我在某处读到,您可以创建一个简单的方法,该方法没有映射到特定路径来处理所有 OPTIONS 请求,如下所示:

@RequestMapping(method = RequestMethod.OPTIONS)
    public ResponseEntity handle() 
        return new ResponseEntity(HttpStatus.NO_CONTENT);
    

但是,当我添加该方法时,我提交的每个请求都表明它找不到到我请求的资源的映射。

有没有一种方法可以在一个方法中处理所有 OPTIONS 请求,而不必为我创建的每个接口都创建一个?

【问题讨论】:

【参考方案1】:

对于那些感兴趣的人,它就像添加“/*”的请求映射一样简单。我现在可以从我的控制器中删除所有其他 OPTIONS 方法,并使用这个单一方法处理所有预检 OPTIONS 请求:

@RequestMapping(method = RequestMethod.OPTIONS, value = "/*")
@ResponseBody
public ResponseEntity handleOptions() 
    return new ResponseEntity(HttpStatus.NO_CONTENT);

另外值得注意的是,我必须将此添加到我的安全配置中,以允许所有请求进行 OPTIONS 调用而不会收到 403 错误(并允许 websockets 正确连接):

http
        .authorizeRequests()
        .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
        .antMatchers("/stomp/**").permitAll()
        .antMatchers("/**").hasRole("USER");

【讨论】:

这是克服预检选项请求的技巧吗?无论如何,它有效。 不,这不是 hack。预检 OPTIONS 请求将始终按定义发生,您可以确保响应有效并包含正确的 CORS 标头。此解决方案 a) 允许您仅定义一个控制器方法来定义所有预检请求的 OPTIONS 响应,并且 b) 防止 Spring Security 阻止 OPTIONS 请求。也许有一些较低级别的方法可以做到这一点,但这是我在 Spring 中能找到的最简单的方法。

以上是关于怎样避免跨域发出OPTIONS请求?的主要内容,如果未能解决你的问题,请参考以下文章

http预请求 options

options预请求

使用 Spring MVC 4 处理跨域预检 AJAX OPTIONS 请求

options请求问题

Chrome 73 中阻止的 CORB OPTIONS 请求

Nginx解决跨域问题