CORS,防止带有授权标头的请求预检
Posted
技术标签:
【中文标题】CORS,防止带有授权标头的请求预检【英文标题】:CORS, prevent preflight of request with Authorization header 【发布时间】:2016-12-28 06:03:36 【问题描述】:当我添加 Authorization
标头时,AngularJS 将我的 POST
请求转换为 OPTIONS
:
$http(
url: ApiEndpoint + 'logout',
method: 'POST',
headers:
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': UserService.getApiKey()
)
我正在使用我在浏览器中测试的 Ionic 开发一个混合移动应用程序,因为它是一个 CORS 请求。
我已经看到this 的问题了。建议的解决方法是更改我所做的Content-Type
,并且它在没有Authorization
的情况下工作。使用Authorization
标头,请求再次更改为 OPTIONS 方法。
您能否提出客户端解决方案,因为您无法控制服务器 API。
谢谢。
【问题讨论】:
预检将在您的情况下触发,因为设置“授权”标头会使您的请求在 MDN 术语中不简单。唯一允许手动设置以分类为 simple 的标题是 Accept、Accept-Language、Content-Language 和 Content-Type。参考:developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS。不确定您是否可以避免飞行前,但您可以在给定的时间范围内缓存请求。 【参考方案1】:正如Developer 所说,CORS 请求将被预检,除非它是simple request。
【讨论】:
【参考方案2】:正如其他人所指出的,您看到的是 CORS 预检请求。
如果您想设置Authorization
标头,则无法避免它们,但如果您控制后端(或愿意使用代理),则有一些解决方法。更多信息:https://damon.ghost.io/killing-cors-preflight-requests-on-a-react-spa/
简而言之:
CORS 预检标头可以被浏览器缓存(将 Access-Control-Max-Age header 设置为应缓存响应的秒数) 可以将授权标头移至 URL 参数(如果这是个好主意,则另当别论) 您可以在没有正确标头的情况下发送 JSON(同样,这不是最好的想法,但是...) 如果它适合您的用例,最简单的解决方案是使用代理,从而完全避免跨域请求【讨论】:
“CORS preflight headers can be cached”——如果你能添加一些关于如何完成的解释会很好。 当然,完成。 (并且我需要在此处添加一些虚假文本,以便此评论至少有 15 个字符长)【参考方案3】:以下答案可能也适用于您正在做的事情 - 尽管如果数据格式正确,您的“Content-Type”标头应该没问题:
How to skip the OPTIONS preflight request in AngularJS
【讨论】:
谢谢,我看到了这个问题,建议的解决方法是更改我所做的Content-Type
,并且它在没有Authorization
的情况下工作。当我添加 Authorization
时,请求更改为 OPTIONS 方法
@Developer 是对的。 Authorization 标头会导致您的请求不是“简单”请求(它不是“安全列表”标头 - 请参阅此处:fetch.spec.whatwg.org/#cors-safelisted-request-header),因此浏览器将执行预检请求。【参考方案4】:
为避免预检请求,只需创建自己的控制器,然后从服务器代码调用其他源 REST 服务。
<pre>
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException
String outputString = request.getParameter("data"); /*Refer the ajax data $.ajax(
url:"callRestApi",
type:'POST',
data:
"data":"data Value"
,
beforeSend: function (xhr)
xhr.setRequestHeader ("Authorization", "Basic " + btoa(uname + ":" + passwd));
,
success:function()
alert("Successfully created JSON data from DB");
,
error:function(textStatus, jqXHR)
alert("Unable to process some of the types, Please check logs for details.");
);*/
HttpURLConnection conn = null;
URL url = new URL("");// just example, in your case pass the URL here
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "");// just example, in your
// case pass the content
// type here
conn.setRequestProperty("Authorization", "");// just example, in your
// case pass the
// authorization key
// here
DataOutputStream outputStream = new DataOutputStream(
conn.getOutputStream());
outputStream.write(outputString.getBytes());
outputStream.flush();
outputStream.close();
StringBuffer sb = new StringBuffer();
if (conn != null && conn.getResponseCode() == 200)
byte[] buffer = new byte[8192];
int bytesRead;
InputStream in = conn.getInputStream();
while ((bytesRead = in.read(buffer)) != -1)
sb.append(new String(buffer, 0, bytesRead, "UTF-8"));
buffer = new byte[8192];
bytesRead = 0;
System.out.println("Output ===>" + sb.toString());
</pre>
在上面的例子中不会有任何预检请求。因为 Rest API 调用将在服务器端完成。
【讨论】:
如果服务器无法访问其他服务器,这将不起作用。以上是关于CORS,防止带有授权标头的请求预检的主要内容,如果未能解决你的问题,请参考以下文章
被 CORS 阻止:预检响应中的 Access-Control-Allow-Headers 不允许请求标头字段授权
Angular CORS 简单请求在 POST 中触发带有 Authorization 标头的预检
被 CORS 策略阻止:预检响应中的 Access-Control-Allow-Headers 不允许请求标头字段授权
Laravel API cors-预检响应中的Access-Control-Allow-Headers不允许请求标头字段授权[重复]