为什么我的JavaScript代码收到“请求的资源上不存在'Access-Control-Allow-Origin'标头”错误,而Postman没有?

mod笔记:这个问题是关于为什么浏览器上的XMLHttpRequest/fetch/等受相同访问策略限制(你会遇到提到CORB或CORS的错误)而Postman不受。这个问题是关于如何修复“No'Access-Control-Allow-Origin'…”错误。这是关于它们发生的原因。

请停止发布

  • 阳光下每种语言/框架的CORS配置。而不是找到相关语言/框架的问题
  • 允许请求绕过CORS的第三方服务
  • 用于关闭各种浏览器的CORS的命令行选项

我试图通过连接到RESTfulapi内置烧瓶来使用javascript进行授权。但是,当我发出请求时,我收到以下错误:

XMLHttpRequest cannot load http://myApiUrl/login.No 'Access-Control-Allow-Origin' header is present on the requested resource.Origin 'null' is therefore not allowed access.

我知道API或远程资源必须设置标头,但是为什么当我通过Chrome扩展名邮递员发出请求时它会起作用?

这是请求代码:

$.ajax({type: 'POST',dataType: 'text',url: api,username: 'user',password: 'pass',crossDomain: true,xhrFields: {withCredentials: true,},}).done(function (data) {console.log('done');}).fail(function (xhr, textStatus, errorThrown) {alert(xhr.responseText);alert(textStatus);});
5772404 次浏览

如果我理解正确的话,您正在对与您的页面不同的域执行XMLHttpRequest相关文档。所以浏览器阻止它,因为它通常允许出于安全原因在同一来源的请求。当您想要执行跨域请求时,您需要做一些不同的事情。

当您使用Postman时,他们不受此策略的限制。引用自跨源XMLHttpRequest

常规网页可以使用XMLHttpRequest对象从远程服务器发送和接收数据,但它们受到同源策略的限制。扩展没有那么有限。扩展可以与其源之外的远程服务器通信,只要它首先请求跨源权限。

警告:使用Access-Control-Allow-Origin: *会使您的API/网站容易受到跨站请求伪造(CSRF)攻击。在使用此代码之前确保您了解风险

如果您使用的是php,解决起来非常简单。只需在处理请求的PHP页面的开头添加以下脚本:

<?php header('Access-Control-Allow-Origin: *'); ?>

如果您使用的是红色节点,您必须通过取消注释以下行来允许node-red/settings.js文件中的CORS

// The following property can be used to configure cross-origin resource sharing// in the HTTP nodes.// See https://github.com/troygoode/node-cors#configuration-options for// details on its contents. The following is a basic permissive set of options:httpNodeCors: {origin: "*",methods: "GET,PUT,POST,DELETE"},

如果您使用的是烧瓶与问题相同;您必须首先安装flask-cors

pip install -U flask-cors

然后在您的应用程序中包含Flaskcors包。

from flask_cors import CORS

一个简单的应用程序将如下所示:

from flask import Flaskfrom flask_cors import CORS
app = Flask(__name__)CORS(app)
@app.route("/")def helloWorld():return "Hello, cross-origin-world!"

有关详细信息,您可以查看烧瓶留档

因为
-调用选项

邮递员正确地调用“POST”,但是当我们调用它时,它将是“OPTIONS”。

对于C#Web服务-Web API

请在标签下的web.config文件中添加以下代码。这将起作用:

<httpProtocol><customHeaders><add name="Access-Control-Allow-Origin" value="*" /></customHeaders></httpProtocol>

请确保您在Ajax调用中没有犯任何错误。

jQuery

$.ajax({url: 'http://mysite.microsoft.sample.xyz.com/api/mycall',headers: {'Content-Type': 'application/x-www-form-urlencoded'},type: "POST", /* or type:"GET" or type:"PUT" */dataType: "json",data: {},success: function (result) {console.log(result);},error: function () {console.log("error");}});

备注:如果您正在寻找下载内容从第三方网站然后这对你没有帮助。您可以尝试以下代码,但不能使用JavaScript。

System.Net.WebClient wc = new System.Net.WebClient();string str = wc.DownloadString("http://mysite.microsoft.sample.xyz.com/api/mycall");

在下面的API调查中,我使用http://example.com而不是超文本传输协议://myApiUrl/登录您的问题,因为这第一个工作。我假设您的页面在http://my-site.local:8088上。

:API和您的页面有不同的域!

你看到不同结果的原因是邮递员:

  • 设置标头Host=example.com(您的API)
  • 未设置标头Origin
  • Postman实际上根本不使用您的网站url(您只在Postman中输入您的API地址)-他只向API发送请求,所以他假设网站与API具有相同的地址(浏览器不假设这一点)

这类似于浏览器在站点和API具有相同域时发送请求的方式(浏览器也设置了标头项Referer=http://my-site.local:8088,但我在Postman中看不到它)。当#1标头未设置时,通常服务器默认允许此类请求。

在此处输入图片描述

这是Postman发送请求的标准方式。但是当您的网站和API有不同的域时,浏览器发送请求的方式不同,然后CORS发生,浏览器自动:

  • 设置标头Host=example.com(您的API)
  • 设置标题Origin=http://my-site.local:8088(您的网站)

(标题RefererOrigin具有相同的值)。现在在Chrome的控制台和网络选项卡中,您将看到:

在此处输入图片描述

在此处输入图片描述

当您有#0时,这是CORS,当服务器检测到这样的请求时,它通常是默认阻止它

当您从本地目录打开超文本标记语言内容时,会设置Origin=null,然后它会发送一个请求。同样的情况是,当您在<iframe>中发送请求时,就像下面的片段一样(但这里根本没有设置Host标头)-一般来说,只要超文本标记语言规范说不透明的起源,您就可以将其转换为Origin=null。有关此的更多信息,您可以找到这里

fetch('http://example.com/api', {method: 'POST'});
Look on chrome-console > network tab

如果您不使用简单的CORS请求,通常浏览器也会在发送主请求之前自动发送一个OPTIONS请求-更多信息是这里。下面的片段显示了它:

fetch('http://example.com/api', {method: 'POST',headers: { 'Content-Type': 'application/json'}});
Look in chrome-console -> network tab to 'api' request.This is the OPTIONS request (the server does not allow sending a POST request)

您可以更改服务器的配置以允许CORS请求。

这是一个打开nginx上的CORS(nginx.conf文件)的示例配置-非常小心为nginx设置always/"$http_origin",为Apache设置"*"-这将从任何域中解除屏蔽CORS(在生产中,而不是明星使用消耗您的API的具体页面广告)

location ~ ^/index\.php(/|$) {...add_header 'Access-Control-Allow-Origin' "$http_origin" always;add_header 'Access-Control-Allow-Credentials' 'true' always;if ($request_method = OPTIONS) {add_header 'Access-Control-Allow-Origin' "$http_origin"; # DO NOT remove THIS LINES (doubled with outside 'if' above)add_header 'Access-Control-Allow-Credentials' 'true';add_header 'Access-Control-Max-Age' 1728000; # cache preflight value for 20 daysadd_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';add_header 'Access-Control-Allow-Headers' 'My-First-Header,My-Second-Header,Authorization,Content-Type,Accept,Origin';add_header 'Content-Length' 0;add_header 'Content-Type' 'text/plain charset=UTF-8';return 204;}}

这是一个打开Apache上的CORS(. htaccess文件)的示例配置

# ------------------------------------------------------------------------------# | Cross-domain Ajax requests                                                 |# ------------------------------------------------------------------------------
# Enable cross-origin Ajax requests.# http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity# http://enable-cors.org/
# <IfModule mod_headers.c>#    Header set Access-Control-Allow-Origin "*"# </IfModule>
# Header set Header set Access-Control-Allow-Origin "*"# Header always set Access-Control-Allow-Credentials "true"
Access-Control-Allow-Origin "http://your-page.com:80"Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"Header always set Access-Control-Allow-Headers "My-First-Header,My-Second-Header,Authorization, content-type, csrf-token"

应用CORS限制是由服务器定义并由浏览器实现的安全功能。

浏览器查看服务器的CORS策略并遵守它。

但是,Postman工具并不关心服务器的CORS策略。

这就是为什么CORS错误出现在浏览器中,而不是在Postman中。

您得到的错误是由于CORS标准,该标准对JavaScript如何执行ajax请求设置了一些限制。

CORS标准是在浏览器中实现的客户端标准。因此,阻止调用完成并生成错误消息的是浏览器,而不是服务器。

Postman没有实现CORS限制,这就是为什么在从Postman进行相同调用时看不到相同错误的原因。

为什么 Postman没有实现CORS吗?CORS定义了相对于发起请求的页面的来源(URL域)的限制。但在Postman中,请求不是来自具有URL的页面,因此CORS不适用。

如果您的网关超时太短,并且您正在访问的资源需要比超时更长的时间来处理,您也可能会收到此错误。这可能是复杂数据库查询等的情况。因此,上述错误代码可以掩盖此问题。只需检查错误代码是否为504,而不是卡米尔的回答或其他内容中的404。如果是504,那么增加网关超时可能会解决问题。

在我的情况下,可以通过在Internet Explorer浏览器中禁用同源策略(CORS)来删除CORS错误,请参阅如何禁用同源策略Internet Explorer。执行此操作后,日志中出现了纯504错误。

解决方案和问题起源

您正在为不同的域创建XMLHttpRequest相关文档,例如:

  1. 域名一:some-domain.com
  2. 域二:some-different-domain.com

域名的这种差异触发了称为SOP同源政策)的CORS跨域资源共享)策略,该策略强制在Ajax、XMLHttpRequest和其他HTTP请求中使用相同的域(因此为起源)。

为什么当我通过Chrome扩展提出请求时它会起作用邮递员?

客户端(大多数浏览器开发工具)可以选择强制执行同源策略。

大多数浏览器强制执行同源策略以防止与CSRFCross-Site Request Forgery)攻击相关的问题。

邮递员作为开发工具选择不强制执行SOP,而某些浏览器强制执行,这就是为什么您可以通过Postman发送您无法使用浏览器通过JS使用XMLHttpRequest发送的请求。

用于浏览器测试目的:

Windows-运行:

chrome.exe --user-data-dir="C://Chrome dev session" --disable-web-security

上面的命令将禁用chrome网络安全。例如,如果您在本地项目中工作,在尝试发出请求时遇到CORS策略问题,您可以使用上面的命令跳过这种类型的错误。基本上它会打开一个新的chrome会话。

您的IP地址未列入白名单,因此您会收到此错误。请后端人员将您正在访问的服务的IP地址列入白名单。

访问控制允许头

要解决此问题,请在后端使用的doGet()doPost()函数中编写这行代码

response.setHeader("Access-Control-Allow-Origin", "*");

而不是"*",您可以输入访问网站的网站或API URL端点,否则它将是公共的。

它通过在全球范围内应用这个中间件来为我工作:

<?php
namespace App\Http\Middleware;
use Closure;
class Cors {public function handle($request, Closure $next) {return $next($request)->header('Access-Control-Allow-Origin', '*')->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')->header('Access-Control-Allow-Headers', "Accept,authorization,Authorization, Content-Type");}}

对我来说,我因为不同的原因遇到了这个问题,远程域被添加到源中,部署的应用程序完美地工作,除了一个终端,我遇到了这个问题:

Origin https://mai-frontend.vercel.app is not allowed by Access-Control-Allow-Origin. Status code: 500

Fetch API cannot load https://sciigo.herokuapp.com/recommendations/recommendationsByUser/8f1bb29e-8ce6-4df2-b138-ffe53650dbab due to access control checks.

更新Heroku数据库表后,我发现我的Heroku数据库表不包含本地表的所有列,一切都运行良好。