使用 CORS 避免预检 OPTIONS 请求

Posted

技术标签:

【中文标题】使用 CORS 避免预检 OPTIONS 请求【英文标题】:Avoiding preflight OPTIONS requests with CORS 【发布时间】:2015-08-04 21:40:30 【问题描述】:

我正在构建一个 Angular 应用程序,该应用程序与使用 ASP.NET Web API 2 构建的 API 进行交互。我正在使用基本身份验证,方法是在每个需要身份验证的请求中发送一个 Authorization 标头:

角度 sn-p:

$http.defaults.headers.common['Authorization'] = authHeader;

请求:

Accept:application/json, text/javascript
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Max-Age:1728000
Authorization:Basic [base64 encoded credential couplet here]
Connection:keep-alive
DNT:1
Host: blah.com
Origin:http://localhost:9000
Referer:http://localhost:9000/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/53

这一切正常,但是每个 GETPOST 请求都会发送一个预检 OPTIONS 请求。这主要影响应用程序的感知速度。我已经阅读了大量关于 CORS“简单请求”的内容,似乎为了避免可怕的预检 OPTIONS 请求是避免在我的请求中添加任何自定义标头。我尝试了很多其他的东西,比如发送text/plainContent-Type,但似乎 Authorization 标头是违反 CORS“简单请求”要求的东西。

所以看来我可能不得不移动 API 以使用基于令牌的身份验证/授权。为了避免预检请求,我似乎需要将令牌放在查询字符串中。这没关系,因为它只是一个小型内部网络应用程序,无论如何只能由几个用户访问。我打算在控制器响应上实现缓存。由于对控制器操作的每个请求都会根据当前经过身份验证的用户在查询字符串中具有不同的令牌,这会使缓存变得无用吗?

所以:

    如何避免预检请求(尽可能使用自定义授权标头) 如果1.) 不可行,并且我转向基于令牌的身份验证,我将无法缓存控制器操作的 API 响应 什么是最广泛使用的方法来避免预检请求并安全地对用户进行身份验证?

nb 我知道在 SO 和网络上的其他地方还有其他几个线程与此有关,但没有一个倾向于提供关于是否可以避免对 GETs 和 @987654334 的预检请求的明确答案@s 使用自定义 HTTP 授权标头时。

【问题讨论】:

1.) 尚无法在所有浏览器和 HTTP 方法中使用:developer.mozilla.org/en-US/docs/Web/HTTP/… 您应该能够使用XMLHttpRequest withCredentials 发送带有授权cookie 的非预检请求。 【参考方案1】:

我认为这篇文章 (How to apply CORS preflight cache to an entire domain) 已经说明了一切——对此你无能为力

一个简单的解决方案是向为您的 Angular 应用程序(例如 nginx)提供服务的代理/网络服务器添加一个反向代理,以通过同一域(例如 nginx)路由您的 RESTful 调用。 appdomain.com/api --> apidomain.com.

【讨论】:

感谢雷托!尽管我很想以适当的方式整理出整个飞行前的事情,但我最终还是选择了这个答案。事实证明,您可以在 IIS 和 Azure 网站中设置反向代理,因此我的客户端也将托管在 Azure Web 应用程序中,并将本地 /api 请求转发到托管 API 的其他 Azure Web 应用程序。参考:ruslany.net/2014/05/using-azure-web-site-as-a-reverse-proxy【参考方案2】:

另一个对我来说似乎工作正常的解决方案。无需设置代理并需要路由到同一个域,可以直接从 nginx 返回预检请求,从而将预检请求所需的时间减少到几毫秒。

这里有一个简单的sn-p,可以和nginx一起使用。

 location / 
    if ($request_method = 'OPTIONS') 
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain charset=UTF-8';
        add_header 'Content-Length' 0;
        return 204;
     

一旦预检请求成功,就可以简单地将“Access-Control-Allow-Origin”和其他必要的东西添加到“GET”、“POST”请求等......

【讨论】:

以上是关于使用 CORS 避免预检 OPTIONS 请求的主要内容,如果未能解决你的问题,请参考以下文章

AWS 中的 403 OPTIONS Cors 错误,预检请求

如何在 CORS 预检 OPTIONS 请求中发送自定义标头?

options请求问题

为啥经过身份验证的 CORS 请求的预检 OPTIONS 请求在 Chrome 中有效,但在 Firefox 中无效?

CORS跨域请求限制-options预检请求

Laravel/React:barryvdh/laravel-cors 处理预检 HTTP OPTIONS 请求