为什么我的JavaScript代码在Postman没有时会在请求的资源上出现“No'Access-Control-Allow-Origin'标头”错误?

问题描述 投票:2151回答:42

我试图通过连接到JavaScript建造的RESTful API使用Flask进行授权。但是,当我发出请求时,我收到以下错误:

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

我知道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);
    });
jquery cors restful-authentication same-origin-policy flask-restless
42个回答
1201
投票

如果我理解正确的话,你正在做一个XMLHttpRequest到一个不同的域,而不是你的页面。因此浏览器会阻止它,因为出于安全原因,它通常允许同一来源的请求。当您想要执行跨域请求时,您需要做一些不同的事情。有关如何实现这一目标的教程是Using CORS

当您使用邮递员时,他们不受此政策的限制。引自Cross-Origin XMLHttpRequest

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


12
投票

如果你不想:

  1. 在Chrome中停用网络安全
  2. 使用JSONP
  3. 使用第三方网站重新路由您的请求

并且您确定您的服务器已启用CORS(此处测试CORS:XHR

然后你需要在你的请求中传入origin参数。此来源必须与您的浏览器与您的请求一起发送的来源相匹配。

你可以在这里看到它:http://www.test-cors.org/

编辑功能将GET和POST请求发送到其他域以获取数据。我设置了解决问题的origin参数。后端是一个mediaWiki引擎。

tldr:在你的调用中添加“origin”参数,这些参数必须是浏览器发送的Origin参数(你不能欺骗origin参数)


10
投票

当我使用AngularJS访问我的API时,我遇到了问题。相同的请求在SoapUI 5.0和ColdFusion中有效。我的GET方法已经有了Access-Control-Allow-Origin标头。

我发现AngularJS提出了“试用”OPTIONS请求。默认情况下,ColdFusion会生成OPTIONS方法,但它没有太多,具体来说这些标头。响应OPTIONS调用生成错误,而不是我故意调用GET。我将下面的OPTIONS方法添加到我的API后,问题已经解决。

http://www.wikinomad.com/app/detail/Campgrounds/3591

10
投票

基于<cffunction name="optionsMethod" access="remote" output="false" returntype="any" httpmethod="OPTIONS" description="Method to respond to AngularJS trial call"> <cfheader name="Access-Control-Allow-Headers" value="Content-Type,x-requested-with,Authorization,Access-Control-Allow-Origin"> <cfheader name="Access-Control-Allow-Methods" value="GET,OPTIONS"> <cfheader name="Access-Control-Allow-Origin" value="*"> <cfheader name="Access-Control-Max-Age" value="360"> </cffunction> ,我创建了一个Chrome浏览器的快捷方式,其中包含所需的参数:shruti's answer enter image description here


8
投票

从服务器请求响应时,我有以下配置,导致相同的错误。

服务器端:enter image description here - >提供REST-API 客户端:SparkJava - >提供浏览器渲染

在服务器端,我不得不将此添加到响应中:

ExtJs6

在客户端,我不得不将此添加到请求中:

Spark.get("/someRestCallToSpark", (req, res) -> {
    res.header("Access-Control-Allow-Origin", "*"); //important, otherwise its not working 
    return "some text";
 });

8
投票

Ext.Ajax.request({ url: "http://localhost:4567/someRestCallToSpark", useDefaultXhrHeader: false, //important, otherwise its not working success: function(response, opts) {console.log("success")}, failure: function(response, opts) {console.log("failure")} }); 提供(Node.js)代码,您可以使用它来设置和运行您自己的CORS代理。它主动维护并提供许多功能来控制代理行为,而不仅仅是基本发送正确的https://github.com/Rob--W/cors-anywhere/响应头。

Access-Control-*详细解释了浏览器如何处理客户端Web应用程序通过JavaScript进行的跨源请求以及必须配置由服务器发送请求的头部,如果可以的话。

如果您需要向其发出请求并获得响应的站点未返回https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS响应标头,则浏览器始终会阻止客户端JavaScript代码直接向其发出的跨源请求。因此,如果站点不是您控制的站点并且可以为其配置行为,那么在这种情况下唯一可行的是代理请求 - 通过您自己运行的代理或通过开放代理。

正如在此处的其他评论中所提到的,有充分的理由不信任您的请求的开放代理。也就是说,如果您知道自己在做什么,并且您认为开放式代理可以满足您的需求,那么Access-Control-Allow-Origin就是可靠,可靠,可维护且运行https://cors-anywhere.herokuapp.com/代码的实例。

与此处提到的其他开放代理(其中一些至少似乎不再可用)一样,它的工作方式是,不是让您的客户端代码直接发送请求,例如,https://github.com/Rob--W/cors-anywhere/,您将其发送给http://foo.com和代理将必要的https://cors-anywhere.herokuapp.com/http://foo.com标头添加到浏览器看到的响应中。


8
投票

您可以通过使用YQL通过Yahoo的服务器代理请求来绕过问题。它只是几行代码:

Access-Control-*

这是与解释的链接:var yql_url = 'https://query.yahooapis.com/v1/public/yql'; var url = 'your api url'; $.ajax({ 'url': yql_url, 'data': { 'q': 'SELECT * FROM json WHERE url="'+url+'"', 'format': 'json', 'jsonCompat': 'new', }, 'dataType': 'jsonp', 'success': function(response) { console.log(response); }, });


6
投票

如果您正在使用https://vverma.net/fetch-any-json-using-jsonp-and-yql.html,即使您启用了Entity Framework,似乎有时也会抛出此错误。我发现错误的发生是因为缺少查询的最终确定。我希望这会在同样的情况下帮助其他人。

以下代码可以抛出CORS错误:

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

要修复它,需要在查询结束时执行using (DBContext db = new DBContext()) { return db.Customers.Select(x => new { Name = x.Name, CustomerId = x.CustomerId, }); } .ToList()等终结调用,如下所示:

.FirstOrDefault()

6
投票

在我的情况下,我使用的是JEE7 JAX-RS应用程序,并且以下技巧对我来说非常有效:

using (DBContext db = new DBContext())
{
    return db.Customers.Select(x => new
    {
        Name = x.Name,
        CustomerId = x.CustomerId,
    }).ToList();
}

5
投票

我成功地能够使用htaccess解决(在我的情况下使用字体),但很明显,OP的要求稍有不同。但是您可以使用FileMatch模式并添加任何类型的扩展名,以便它不会产生交叉错误。

@GET
    @Path("{id}")
    public Response getEventData(@PathParam("id") String id) throws FileNotFoundException {
        InputStream inputStream = getClass().getClassLoader().getResourceAsStream("/eventdata/" + id + ".json");
        JsonReader jsonReader = Json.createReader(inputStream);
        return Response.ok(jsonReader.readObject()).header("Access-Control-Allow-Origin", "*").build();
    }

<IfModule mod_headers.c> <FilesMatch "\.(ttf|ttc|otf|eot|woff|woff2|font.css|css)$"> Header set Access-Control-Allow-Origin "*" </FilesMatch> </IfModule>


4
投票

热门问题 - 如果你已经阅读了这篇文章而另外没有其他任何内容有助于另一件事。如果您有一个CDN,如Akamai,Limelight或类似的CDN,您可能需要检查您拥有的资源URI的缓存密钥。如果它不包含Origin标头值,则可能在从另一个Origin请求时返回缓存的响应。我们只花了半天时间调试这个。 CDN配置已更新为仅包含我们的一些选定域的Origin值,并将其设置为null。这似乎有效,并允许来自我们已知域的浏览器查看我们的资源。当然所有其他答案都是到达这里的先决条件,但如果CDN是您浏览器的第一跳,则需要查看。

在我们的案例中,我们可以看到一些请求进入我们的服务但不是几乎没有网站发送的卷。这向我们指出了CDN。我们能够返回并看到原始请求是从直接请求提供的,而不是浏览器AJAX调用的一部分,并且不包括响应头Access-Control-Allow-Origin。显然,CDN缓存了这个值。 Akamai CDN配置调整将原始请求标头值视为匹配的一部分似乎已使其适用于我们。


504
投票

这不是生产修复或者必须向客户端显示应用程序时,这仅在UI和后端开发位于不同服务器上并且在生产中它们实际上位于同一服务器上时才有用。例如:在为任何应用程序开发UI时,如果需要在本地测试它指向后端服务器,那么这是一个完美的修复。对于生产修复,必须将CORS头添加到后端服务器以允许跨源访问。

简单的方法是在谷歌浏览器中添加扩展名以允许使用CORS进行访问。

(Qazxswpoi)

只要您希望不允许访问“access-control-allow-origin”标头请求,只需启用此扩展。

要么

在Windows中,将此命令粘贴到运行窗口中

https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=en-US

这将打开一个新的Chrome浏览器,允许访问没有'access-control-allow-origin'标头请求。


4
投票

对于GoLang API:

首先你可以看看https://httpd.apache.org/docs/2.4/mod/core.html#filesmatch来了解CORS是什么。据我所知,CORS是否允许Origin Of Request访问Server Resource。

您可以通过在服务器响应的MDN CORS Doc中设置Access-Control-Allow-Origin来限制哪个请求源可以访问服务器。

例如,在服务器响应中设置以下标头意味着只有从Header发送的请求才能访问您的服务器:

http://foo.example

以及允许从任何来源(或域)发送的请求:

Access-Control-Allow-Origin: http://foo.example

正如我在错误消息中所知,Access-Control-Allow-Origin: * 意味着服务器的资源,所以requested resource意味着你没有在服务器响应中设置No 'Access-Control-Allow-Origin' header is present on the requested resource.头,或者你设置但是请求的来源不是Access-Control-Allow-Origin中的列表所以不允许请求访问:

请求的资源上不存在“Access-Control-Allow-Origin”标头。因此不允许原点'null'访问。

在GoLang中,我使用Access-Control-Allow-Origin包在gorilla/mux上构建API服务器,并且我通过将localhost:9091添加到响应头来允许CORS:

"Access-Control-Allow-Origin", "*"

我在客户端使用JavaScript,在func main() { // API Server Code router := mux.NewRouter() // API route is /people, //Methods("GET", "OPTIONS") means it support GET, OPTIONS router.HandleFunc("/people", GetPeople).Methods("GET", "OPTIONS") log.Fatal(http.ListenAndServe(":9091", router)) } // Method of '/people' route func GetPeople(w http.ResponseWriter, r *http.Request) { // Allow CORS by setting * in sever response w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Headers", "Content-Type") json.NewEncoder(w).Encode("OKOK") } 上,Chrome的请求可以成功地从服务器localhost:9092获得“OKOK”。

localhost:9091

此外,您可以通过function GetPeople() { try { var xhttp = new XMLHttpRequest(); xhttp.open("GET", "http://localhost:9091/people", false); xhttp.setRequestHeader("Content-type", "text/html"); xhttp.send(); var response = JSON.parse(xhttp.response); alert(xhttp.response); } catch (error) { alert(error.message); } } 等工具检查您的请求/响应标头。


4
投票

如果您从浏览器收到此错误消息:

Fiddler

当您尝试向远程服务器执行Ajax POST / GET请求时,请忘记这个简单的修复:

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '…' is therefore not allowed access

您真的需要,特别是如果您只使用JavaScript来执行Ajax请求,内部代理将接收您的查询并将其发送到远程服务器。

首先在您的JavaScript代码中,对您自己的服务器执行Ajax调用,例如:

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

然后,创建一个名为proxy.php的简单PHP文件来包装POST数据,并将它们作为参数附加到远程URL服务器。我举例说明了如何使用Expedia Hotel搜索API绕过此问题:

$.ajax({
    url: yourserver.com/controller/proxy.php,
    async: false,
    type: "POST",
    dataType: "json",
    data: data,
    success: function (result) {
        JSON.parse(result);
    },
    error: function (xhr, ajaxOptions, thrownError) {
        console.log(xhr);
    }
});

通过做:

if (isset($_POST)) {
  $apiKey = $_POST['apiKey'];
  $cid = $_POST['cid'];
  $minorRev = 99;

  $url = 'http://api.ean.com/ean-services/rs/hotel/v3/list?' . 'cid='. $cid . '&' . 'minorRev=' . $minorRev . '&' . 'apiKey=' . $apiKey;

  echo json_encode(file_get_contents($url));
 }

您只是在执行相同的查询,但在服务器端,之后,它应该可以正常工作。

答案从echo json_encode(file_get_contents($url)); 复制并粘贴


4
投票

如果你想在后端(在Flask中)修复它,而不是在前端,我会完全推荐Flask CORS Python包。 NizarBsb

使用app.py中的一个简单行,您可以自动插入标准,允许任何原始标题,或根据需要自定义。


3
投票

很多时候,这种情况发生在我从javascript到我的php api,因为有几个原因之一。我忘了把Flask CORS放在一个。这对跨子域访问很有帮助。另一个原因是因为在jQuery ajax请求中我指定了一个特定的dataType并返回一个不同的dataType,所以它抛出了一个错误。

此错误的最后和最突出的原因是您请求的页面上存在解析错误。如果您在浏览器中点击该页面网址的可能性很大,您将看到一个解析错误,并且您将有一个行号来解决该问题。

我希望这可以帮助别人。我每次花了一段时间来调试这个,我希望我有一份要核实的清单。


3
投票

在JSONP请求中,您应该捕获“jsonpCallback”并将其发回:

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

在后端(如果您使用PHP作为后端):

$.ajax({
      url: lnk,
      type: 'GET',
      crossDomain: true,
      dataType: 'jsonp',
      success: function (ip) { console.log(ip.ip); },
      error: function (err) { console.log(err) }
});

在这种情况下,后端响应如下:

jQuery331009526199802841284_1533646326884({ “IP”: “192.168.1.1”})

但是您可以在前端手动设置“jsonpCallback”并在后端端捕获它:

echo $_GET['callback'].'({"ip":"192.168.1.1"})';

在这种情况下,后端响应如下:

get_ip({ “IP”: “192.168.1.1”})


2
投票

我在Angular中使用$.ajax({ url: lnk, type: 'GET', crossDomain: true, dataType: 'jsonp', jsonpCallback: 'get_ip', success: function (ip) { console.log(ip.ip); }, error: function (err) { console.log(err) } }); 得到了这个错误。我需要使用$http.get代替。


2
投票

在我的网站上(基于.NET)我刚刚添加了这个:

$http.jsonp

非常感谢<system.webServer> <httpProtocol> <customHeaders> <add name="Access-Control-Allow-Origin" value="*" /> <add name="Access-Control-Allow-Headers" value="Content-Type" /> <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" /> </customHeaders> </httpProtocol> </system.webServer> 视频。


2
投票

CORS适合你。

CORS是“跨源资源共享”,是一种发送跨域请求的方法。现在,XMLHttpRequest2和Fetch API都支持CORS。

但它有其局限性。服务器需要特定声明Access-Control-Allow-Origin,并且不能设置为'*'。

如果你想任何来源可以向你发送请求,你需要JSONP(也需要设置Access-Control-Allow-Origin,但可以是'*')。

对于很多请求方式,如果你不知道该选择什么,我认为你需要一个功能齐全的组件来做到这一点。让我介绍一个简单的组件this


如果您使用的是现代浏览器(> Internet Explorer9,Chrome,Firefox,Edge等),建议您使用简单但美观的组件catta。它没有依赖关系,小于3 KB,它支持Fetch,Ajax和JSONP,具有相同的死语法和选项。

https://github.com/Joker-Jelly/catta

它还支持导入项目的所有方式,如ES6模块,CommonJS甚至HTML中的catta('./data/simple.json').then(function (res) { console.log(res); });


2
投票

为了完整性,<script>允许角色:

Apache

2
投票

这个解决方案绝对适合您。添加自定义消息句柄:

Header set Access-Control-Allow-Origin "http://www.allowonlyfromthisurl.com"
Header set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
Header set Access-Control-Max-Age "1000"
Header set Access-Control-Allow-Headers "x-requested-with, Content-Type, Accept-Encoding, Accept-Language, Cookie, Referer"

在webapiconfig.cs中注册:

public class CustomHeaderHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
        var referrer = request.Headers.Referrer;
        if (referrer != null && !response.Headers.Contains("Access-Control-Allow-Origin"))
        {
            response.Headers.Add("Access-Control-Allow-Origin", referrer.Scheme + "://" + referrer.Authority);
        }
        return response;
    }
}

如果您使用SignalR,请在config.MessageHandlers.Add(new CustomHeaderHandler()); 文件中添加以下代码:

globle.asax.cs

335
投票

如果你可以作为回报处理chrome.exe --user-data-dir="C:/Chrome dev session" --disable-web-security ,那么尝试使用JSON(注意结尾处的P)来表达域之间的说话:

JSONP

了解有关使用JSONP $.ajax({ type: "POST", dataType: 'jsonp', ...... etc ...... 的更多信息:

JSONP的出现 - 本质上是一个双方同意的跨站点脚本黑客 - 为强大的内容混搭打开了大门。许多着名网站都提供JSONP服务,允许您通过预定义的API访问其内容。


2
投票

这些答案中的大多数都告诉用户如何将CORS标头添加到他们控制的服务器中。

但是,如果您需要来自服务器的数据而无法在网页中控制,则一种解决方案是在页面上创建脚本标记,将src属性设置为没有CORS标头的API端点,然后加载该数据到页面上:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    var referrer = Request.UrlReferrer;
    if (Context.Request.Path.Contains("signalr/") && referrer != null)
    {
        Context.Response.AppendHeader("Access-Control-Allow-Origin", referrer.Scheme + "://" + referrer.Authority);
    }
}

211
投票

警告:在生产中使用此答案可能会导致安全问题,即任何人都可以调用您的API /服务,其URL包括攻击者。您必须使用会话和cookie进行身份验证,以防止您的API /服务遭受此攻击。您的API /服务容易受到here(CSRF)的攻击。

如果你使用cross-site request forgery,解决起来非常简单。只需在处理请求的PHP页面的开头添加以下脚本:

PHP

如果您使用的是<?php header('Access-Control-Allow-Origin: *'); ?> ,则必须通过取消注释以下行来允许Node-red文件中的CORS:

node-red/settings.js

如果你使用// 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

一个简单的应用程序将是

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!"


176
投票

我希望有人在很久以前与我分享这个网站flask documentation与构建和依赖我自己的代理相比,它可以节省大量时间。但是,当您转向生产时,拥有自己的代理是最好的选择,因为您仍然可以控制数据的所有方面。

一切你需要的:

http://cors.io/


72
投票

如果您使用的是https://cors.io/?http://HTTP_YOUR_LINK_HERE,请尝试:

Node.js

更多信息:app.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); next(); });


66
投票

使用Ajax存在跨域问题。你必须确保你在相同的CORS on ExpressJS路径上访问你的文件没有http://(或从www.访问并发布到相同的路径,包括http://www.),当通过www.路径访问时,浏览器认为这是另一个域,所以你看到问题出在哪里是。您正在发布到其他域,并且浏览器会因原始问题阻止流。

如果www.未放置在您请求的同一主机上,则流被阻止,您将需要找到另一种与API通信的方式。


54
投票

因为 $ .ajax({type:“POST” - 调用OPTIONS $ .post( - 调用POST

两者都是不同的Postman称之为“POST”,但当我们称之为“OPTIONS”时

对于c#web服务 - webapi

请在<system.webServer>标记下的web.config文件中添加以下代码。这会奏效

API

请确保您在ajax呼叫中没有犯任何错误

jQuery的

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

Angular 4问题请参考:$.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。

http://www.hubfly.com/blog/solutions/how-to-fix-angular-4-api-call-issues/

22
投票

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

简介:纯JavaScript CORS替代/ polyfill。无需服务器配置 - 只需在要与之通信的域上添加proxy.html。该库使用XHook挂钩所有XDomain,因此XDomain应该与任何库一起使用。

© www.soinside.com 2019 - 2024. All rights reserved.