为什么当我的JavaScript代码在请求的资源上没有出现 "No 'Access-Control-Allow-Origin' header is present on the requested resource "的错误?

javascript jquery cors same-origin-policy flask-restless


注释 :这个问题是关于为什么Postman不受XMLHttpRequest一样的CORS限制。 此问题与如何解决“无'Access-Control-Allow-Origin'...”错误无关

请停止发布


我正在尝试通过连接到内置的RESTful API Flask使用JavaScript进行授权。 但是,当我发出请求时,出现以下错误:

XMLHttpRequest无法加载http:// myApiUrl / login 。 所请求的资源上不存在“ Access-Control-Allow-Origin”标头。 因此,不允许访问原始“空”。

我知道API或远程资源必须设置标头,但是当我通过Chrome扩展程序Postman发出请求时,为什么它可以工作?

这是请求代码。

$.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);
    });




Answer 1 MD. Sahib Bin Mahboob


如果我理解正确,那么您正在向页面所在的其他域执行XMLHttpRequest 。 因此,由于安全原因,浏览器通常会阻止来自同一来源的请求,因此阻止了它。 当您想进行跨域请求时,需要做一些不同的事情。 有关如何实现此目标的教程是使用CORS

使用邮递员时,它们不受此政策的限制。 引用自跨域XMLHttpRequest

常规的网页可以使用XMLHttpRequest对象来发送和接收来自远程服务器的数据,但它们受到同样的源策略的限制。而扩展就没有这么多限制了。一个扩展可以与远程服务器进行对话,只要它首先请求跨源权限,就可以与源外的远程服务器进行对话。




Answer 2 Shady Sherif


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

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

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

如果使用的是Node-red ,则必须通过取消注释以下行来允许在 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与问题相同; 您必须先安装 flask-cors

$ pip install -U flask-cors

然后在你的应用中加入Flask cors。

from flask_cors import CORS

一个简单的应用程序将看起来像:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/")
def helloWorld():
  return "Hello, cross-origin-world!"

有关更多详细信息,您可以查看Flask文档




Answer 3 George Livingston


Because
$ .ajax({type:“ POST” -调用OPTIONS
$ .post( -呼叫POST

两者是不同的。Postman正确的叫法是 "POST",但当我们叫它的时候,就会是 "OPTIONS"。

对于C#Web服务-Web API

请在<system.webServer>标记下的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");
    }
});

Angular 4问题-请参考http://www.hubfly.com/blog/solutions/how-to-fix-angular-4-api-call-issues/

注意:如果您要从第三方网站下载内容那么这将无济于事 。 您可以尝试以下代码,但不能尝试JavaScript。

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



Answer 4 Gopinath


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

浏览器会查看服务器的CORS策略并尊重它。

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

这就是为什么在浏览器中出现CORS错误,但在Postman中却没有出现的原因。




Answer 5 Kamil Kiełczewski


在下面的API调查中,我使用了http://example.com而不是您的问题中的http:// myApiUrl / login ,因为第一个有效。

我认为您的页面位于http://my-site.local:8088上

之所以看到不同的结果,是因为邮递员。

  • 设置标头 Host=example.com (您的API)
  • 未设置标头 Origin

这类似于浏览器在站点和API具有相同域时发送请求的方式(浏览器还设置了标头项目 Referer=http://my-site.local:8088 ,但是我在Postman中看不到它) 。 如果设置 Origin 标头,则通常服务器默认情况下会允许此类请求。

Enter image description here

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

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

(标头 Referer 具有与 Origin 相同的值)。 现在,在Chrome的“ 控制台和网络”标签中,您将看到:

Enter image description here

Enter image description here

当您拥有 Host != Origin 这就是CORS,并且服务器检测到这样的请求时,通常默认情况下阻止它

当您从本地目录打开HTML内容时,将设置 Origin=null 并发送请求。 同样的情况是,当您在 <iframe> 内部发送请求时,如下面的代码片段所示(但这里根本没有设置 Host 标头)-通常,在HTML规范中所有显示不透明来源的地方,都可以将其转换为 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 (nginx.conf文件) 打开CORS的示例配置-务必 always/"$http_origin" 为nginx设置always /“ $ http_origin” ,为Apache设置 "*" ,这非常小心-这将阻止来自任何域的CORS。

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 days
        add_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"