http跨域预检问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了http跨域预检问题相关的知识,希望对你有一定的参考价值。

参考技术A 昨天的项目碰到个比较棘手的问题。前端发送ajax请求时,总会在真实请求前多一次请求方法为OPTIONS的请求,而且该请求返回403,导致真实请求失败。后来查阅资料,大致了解了产生该问题的原因及原理,即跨域预检。本文只给出解决方法,不再详述原理,详细可见 简单跨域请求和带预检的跨域请求

解决方法也是比较简单,主要是开启后台的options的验证即可。作者使用spirngboot的项目,主要通过拦截器拦截当前的options请求,开启options验证。

springboot添加拦截器

以上,即可完成因为跨域预检导致的请求失败的问题。

跨域 REST POST 进行预检但没有跟进

【中文标题】跨域 REST POST 进行预检但没有跟进【英文标题】:Cross Domain REST POST Does Preflight Check But No Follow Up 【发布时间】:2018-05-21 00:05:11 【问题描述】:

我是网络编程的新手,所以请耐心等待。我在 python 烧瓶中创建了一个简单的 REST API,并使用 Apache 2.4 托管它。我已经通过 cURL 对其进行了测试,并且可以正常工作。现在我正在尝试通过带有 jQ​​uery 的 Web 界面访问它。

REST api 位于 http://api.localhost,访问它的网站位于 http://localhost。

我用来尝试执行 POST 的代码如下所示:

    $.ajax(
        type: 'POST',
        url: 'http://api.localhost/auth',
        data: '"username":"user1", "password":"abcxyz"',
        success: function(data)  console.log(data); alert('data: ' + data);  ,
        contentType: "application/json",
        dataType: 'json'
    );

但是,成功功能似乎没有运行。查看开发控制台(f12)我可以看到,而不是对该 URL 的 POST,并且发出了 OPTIONS HTTP 请求。我的理解是这是一个跨域资源共享 (CORS) 预检检查,以确保 localhost 可以访问 api.localhost。

我已将以下几行添加到我的 api.localhost 的 apache 配置中:

Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS"

它似乎正在工作,因为 OPTIONS 请求返回 200(并且没有其他数据)。但是,没有后续行动。我的理解是,因为服务器说任何人都可以 POST 到 api.localhost,所以它应该继续执行下一步,但它没有。

以下是预检请求标头:

Host: api.localhost
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101
Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: http://localhost
Connection: keep-alive
Cache-Control: max-age=0

这是同一请求的响应标头(请记住,状态 200):

Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Origin: *
Allow: POST, OPTIONS
Connection: Keep-Alive
Content-Encoding: gzip
Content-Length: 20
Content-Type: text/html; charset=utf-8
Date: Thu, 07 Dec 2017 00:17:08 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.29 (Debian)
Vary: Accept-Encoding

您可以看到服务器说任何域都可以 (*) 并且 POST 可以。但是,没有后续的 POST。我错过了什么?

谢谢。

【问题讨论】:

尝试将 '*' 更改为 'http://localhost' 并向 ajax 请求添加错误处理程序 【参考方案1】:

http://api.localhost/auth 也必须发送Access-Control-Allow-Headers: content-type

因此,您还需要在 Apache 配置中添加以下内容:

Header always set Access-Control-Allow-Headers "content-type"

这是必要的,因为您的前端代码中的 contentType: "application/json" 部分会在请求中添加一个 Content-Type: application/json 标头,并且除 text/plainapplication/x-www-form-urlencodedmultipart/form-data 之外的任何 Content-Type 请求标头的值都会触发浏览器发送 CORS 预检 OPTIONS 请求。

因此,如果您的 http://api.localhost/auth 服务器发回 Access-Control-Allow-Headers: content-type 响应标头,这应该会导致预检成功,从而导致浏览器继续从您的前端代码发出 POST 请求。

【讨论】:

看起来它正在为每个请求进行预检。这将使请求数量增加一倍。有什么办法吗? 你可以让你的 Apache 服务器也发送 Access-Control-Max-Age 响应头,它告诉浏览器缓存 OPTIONS 响应,以及多长时间。 developer.mozilla.org/en-US/docs/Web/HTTP/Headers/…。但是您可能不想将其设置为高于 600(=10 分钟),因为如果您这样做,Chrome 无论如何都会将其限制为 600(也就是说,在 Chrome 中,OPTIONS 响应将永远不会被缓存超过 10分钟)。 太棒了。谢谢。即使是 5 秒也是巨大的。假设第一次加载页面时,我请求了 10 个方法。这将产生 20 个请求,但即使是 5 秒的缓存,也会将其降低到 11 个。

以上是关于http跨域预检问题的主要内容,如果未能解决你的问题,请参考以下文章

为啥跨域 HEAD 请求需要预检?

跨域请求被阻止原因:CORS 预检通道未成功

跨域 REST POST 进行预检但没有跟进

前端跨域 OPTIONS 预检问题

无法调用我的 api 抛出错误不允许需要预检的跨域请求

为啥我的跨域 POST 请求预检了 OPTIONS 请求?