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 不允许请求标头字段授权

如何使用授权标头发出 GET CORS 请求

Laravel API cors-预检响应中的Access-Control-Allow-Headers不允许请求标头字段授权[重复]

Slim 框架上 CORS 期间的预检授权标头