简体   繁体   English

尝试使用 fetch 和 pass in 模式:no-cors

[英]Trying to use fetch and pass in mode: no-cors

I can hit this endpoint, http://catfacts-api.appspot.com/api/facts?number=99 via Postman and it returns JSON我可以通过 Postman 到达这个端点http://catfacts-api.appspot.com/api/facts?number=99并返回JSON

Additionally I am using create-react-app and would like to avoid setting up any server config.此外,我正在使用 create-react-app 并希望避免设置任何服务器配置。

In my client code I am trying to use fetch to do the same thing, but I get the error:在我的客户端代码中,我试图使用fetch来做同样的事情,但我得到了错误:

No 'Access-Control-Allow-Origin' header is present on the requested resource.请求的资源上不存在“Access-Control-Allow-Origin”header。 Origin ' http://localhost:3000 ' is therefore not allowed access.因此,不允许访问来源“ http://localhost:3000 ”。 If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。

So I am trying to pass in an object, to my Fetch which will disable CORS, like so:所以我试图将 object 传递给我的 Fetch,这将禁用 CORS,如下所示:

fetch('http://catfacts-api.appspot.com/api/facts?number=99', { mode: 'no-cors'})
  .then(blob => blob.json())
  .then(data => {
    console.table(data);
    return data;
  })
  .catch(e => {
    console.log(e);
    return e;
  });

Interestingly enough the error I get is actually a syntax error with this function.有趣的是,我得到的错误实际上是这个 function 的语法错误。 I am not sure my actual fetch is broken, because when I remove the { mode: 'no-cors' } object, and supply it with a different URL it works just fine.我不确定我的实际fetch是否损坏,因为当我删除 { mode: 'no-cors' } object 并为其提供不同的 URL 时,它工作得很好。

I have also tried to pass in the object { mode: 'opaque'} , but this returns the original error from above.我也尝试传入 object { mode: 'opaque'} ,但这会从上面返回原始错误。

I belive all I need to do is disable CORS.. What am I missing?我相信我需要做的就是禁用 CORS .. 我错过了什么?

mode: 'no-cors' won't magically make things work. mode: 'no-cors'不会神奇地使事情正常进行。 In fact it makes things worse, because one effect it has is to tell browsers, “Block my frontend JavaScript code from seeing contents of the response body and headers under all circumstances.”事实上,它让事情变得更糟,因为它的一个效果是告诉浏览器, “在任何情况下都阻止我的前端 JavaScript 代码查看响应正文和标头的内容。” Of course you never want that.当然,你永远不想那样。

What happens with cross-origin requests from frontend JavaScript is that browsers by default block frontend code from accessing resources cross-origin.来自前端 JavaScript 的跨域请求会发生什么,浏览器默认阻止前端代码访问跨域资源。 If Access-Control-Allow-Origin is in a response, then browsers relax that blocking and allow your code to access the response.如果Access-Control-Allow-Origin在响应中,则浏览器会放松该阻止并允许您的代码访问响应。

But if a site sends no Access-Control-Allow-Origin in its responses, your frontend code can't directly access responses from that site.但是,如果站点在其响应中未发送Access-Control-Allow-Origin ,则您的前端代码无法直接访问来自该站点的响应。 In particular, you can't fix it by specifying mode: 'no-cors' (in fact that'll ensure your frontend code can't access the response contents).特别是,您无法通过指定mode: 'no-cors'来修复它(实际上这将确保您的前端代码无法访问响应内容)。

However, one thing that will work: if you send your request through a CORS proxy .但是,有一件事起作用:如果您通过CORS 代理发送请求

You can also easily deploy your own proxy to Heroku in just 2-3 minutes, with 5 commands:您还可以在 2-3 分钟内轻松地将自己的代理部署到 Heroku,只需 5 个命令:

git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master

After running those commands, you'll end up with your own CORS Anywhere server running at, for example, https://cryptic-headland-94862.herokuapp.com/ .运行这些命令后,您将拥有自己的 CORS Anywhere 服务器,例如https://cryptic-headland-94862.herokuapp.com/

Prefix your request URL with your proxy URL;在您的请求 URL 前加上您的代理 URL; for example:例如:

https://cryptic-headland-94862.herokuapp.com/https://example.com

Adding the proxy URL as a prefix causes the request to get made through your proxy, which:添加代理 URL 作为前缀会导致请求通过您的代理发出,其中:

  1. Forwards the request to https://example.com .将请求转发到https://example.com
  2. Receives the response from https://example.com .接收来自https://example.com的响应。
  3. Adds the Access-Control-Allow-Origin header to the response.Access-Control-Allow-Origin标头添加到响应中。
  4. Passes that response, with that added header, back to the requesting frontend code.将该响应连同添加的标头一起传递回请求的前端代码。

The browser then allows the frontend code to access the response, because that response with the Access-Control-Allow-Origin response header is what the browser sees.然后浏览器允许前端代码访问响应,因为带有Access-Control-Allow-Origin响应标头的响应是浏览器看到的。

This works even if the request is one that triggers browsers to do a CORS preflight OPTIONS request, because in that case, the proxy also sends back the Access-Control-Allow-Headers and Access-Control-Allow-Methods headers needed to make the preflight successful.即使请求是触发浏览器执行 CORS 预检OPTIONS请求的请求,这也有效,因为在这种情况下,代理还会发回制作所需的Access-Control-Allow-HeadersAccess-Control-Allow-Methods标头预检成功。


I can hit this endpoint, http://catfacts-api.appspot.com/api/facts?number=99 via Postman我可以通过 Postman 访问这个端点http://catfacts-api.appspot.com/api/facts?number=99

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS explains why it is that even though you can access the response with Postman, browsers won't let you access the response cross-origin from frontend JavaScript code running in a web app unless the response includes an Access-Control-Allow-Origin response header. https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS解释了为什么即使您可以使用 Postman 访问响应,浏览器也不允许您从前端访问跨域响应除非响应包含Access-Control-Allow-Origin响应标头,否则在 Web 应用程序中运行的 JavaScript 代码。

http://catfacts-api.appspot.com/api/facts?number=99 has no Access-Control-Allow-Origin response header, so there's no way your frontend code can access the response cross-origin. http://catfacts-api.appspot.com/api/facts?number=99没有Access-Control-Allow-Origin响应标头,因此您的前端代码无法跨域访问响应。

Your browser can get the response fine and you can see it in Postman and even in browser devtools—but that doesn't mean browsers expose it to your code.你的浏览器可以得到很好的响应,你可以在 Postman 甚至浏览器开发工具中看到它——但这并不意味着浏览器会将它暴露给你的代码。 They won't, because it has no Access-Control-Allow-Origin response header.他们不会,因为它没有Access-Control-Allow-Origin响应标头。 So you must instead use a proxy to get it.因此,您必须改为使用代理来获取它。

The proxy makes the request to that site, gets the response, adds the Access-Control-Allow-Origin response header and any other CORS headers needed, then passes that back to your requesting code.代理向该站点发出请求,获取响应,添加Access-Control-Allow-Origin响应标头和所需的任何其他 CORS 标头,然后将其传递回您的请求代码。 And that response with the Access-Control-Allow-Origin header added is what the browser sees, so the browser lets your frontend code actually access the response.添加了Access-Control-Allow-Origin标头的响应是浏览器看到的,因此浏览器允许您的前端代码实际访问响应。


So I am trying to pass in an object, to my Fetch which will disable CORS所以我试图将一个对象传递给我的 Fetch,这将禁用 CORS

You don't want to do that.你不想那样做。 To be clear, when you say you want to “disable CORS” it seems you actually mean you want to disable the same-origin policy .需要明确的是,当您说要“禁用 CORS”时,似乎实际上您的意思是要禁用同源策略 CORS itself is actually a way to do that — CORS is a way to loosen the same-origin policy, not a way to restrict it. CORS 本身实际上是一种方法——CORS 是一种放松同源策略的方法,而不是一种限制它的方法。

But anyway, it's true you can—in your local environment—do suff like give a browser runtime flags to disable security and run insecurely, or you can install a browser extension locally to get around the same-origin policy, but all that does is change the situation just for you locally.但无论如何,你确实可以——在你的本地环境中——提供一个浏览器运行时标志来禁用安全性并不安全地运行,或者你可以在本地安装一个浏览器扩展来绕过同源策略,但所做的只是只为您在本地改变情况。

No matter what you change locally, anybody else trying to use your app is still going to run into the same-origin policy, and there's no way you can disable that for other users of your app.无论您在本地进行什么更改,尝试使用您的应用程序的其他任何人仍然会遇到同源策略,并且您无法为您的应用程序的其他用户禁用该策略。

You most likely never want to use mode: 'no-cors' in practice except in a few limited cases , and even then only if you know exactly what you're doing and what the effects are.您很可能永远不想在实践中使用mode: 'no-cors' ,除非在一些有限的情况下,即使那样,只有在您确切知道自己在做什么以及效果是什么的情况下。 That's because what setting mode: 'no-cors' actually says to the browser is, “Block my frontend JavaScript code from looking into the contents of the response body and headers under all circumstances.”那是因为设置mode: 'no-cors'实际上对浏览器说的是, “在任何情况下都阻止我的前端 JavaScript 代码查看响应正文和标头的内容。” In most cases that's obviously really not what you want.在大多数情况下,这显然不是您想要的。


As far as the cases when you would want to consider using mode: 'no-cors' , see the answer at What limitations apply to opaque responses?至于您考虑使用mode: 'no-cors' ,请参阅哪些限制适用于不透明响应? for the details.详情。 The gist of it is:它的要点是:

  • In the limited case when you're using JavaScript to put content from another origin into a <script> , <link rel=stylesheet> , <img> , <video> , <audio> , <object> , <embed> , or <iframe> element (which works because embedding of resources cross-origin is allowed for those)—but for some reason you don't want to/can't do that just by having the markup of the document use the resource URL as the href or src attribute for the element.在有限的情况下,当您使用 JavaScript 将来自另一个来源的内容放入<script><link rel=stylesheet><img><video><audio><object><embed><iframe>元素(之所以有效,是因为它们允许跨域嵌入资源)——但出于某种原因,您不想/不能仅通过让文档的标记使用资源 URL 作为元素的hrefsrc属性。

  • When the only thing you want to do with a resource is to cache it.当您想要对资源做的唯一事情就是缓存它时。 As alluded to in What limitations apply to opaque responses?正如在哪些限制适用于不透明响应中所提到的那样? , in practice the scenario that's for is when you're using Service Workers, in which case the API that's relevant is the Cache Storage API . ,在实践中,当您使用 Service Worker 时,相关的 API 就是Cache Storage API

But even in those limited cases, there are some important gotchas to be aware of;但即使在那些有限的情况下,也有一些重要的问题需要注意; see the answer at What limitations apply to opaque responses?请参阅哪些限制适用于不透明响应? for the details.详情。


I have also tried to pass in the object { mode: 'opaque'}我也尝试过传入对象{ mode: 'opaque'}

There is no 'opaque' request mode — opaque is instead just a property of the response , and browsers set that opaque property on responses from requests sent with no-cors mode.没有'opaque'请求模式—— opaque只是响应的一个属性,浏览器在以no-cors模式发送的请求的响应上设置该不透明属性。

But incidentally the word opaque is a pretty explicit signal about the nature of the response you end up with: “opaque” means you can't see into any of its details;但顺便说一句,不透明这个词是一个非常明确的信号,表明您最终得到的响应的性质:“不透明”意味着您无法看到它的任何细节; it blocks you from seeing.它阻止你看到。

So if you're like me and developing a website on localhost where you're trying to fetch data from Laravel API and use it in your Vue front-end, and you see this problem, here is how I solved it:所以如果你像我一样在 localhost 上开发一个网站,你试图从 Laravel API 获取数据并在你的 Vue 前端使用它,你看到了这个问题,这就是我解决它的方法:

  1. In your Laravel project, run command php artisan make:middleware Cors .在你的 Laravel 项目中,运行命令php artisan make:middleware Cors This will create app/Http/Middleware/Cors.php for you.这将为您创建app/Http/Middleware/Cors.php
  2. Add the following code inside the handles function in Cors.php :Cors.phphandles函数中添加以下代码:

     return $next($request) ->header('Access-Control-Allow-Origin', '*') ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  3. In app/Http/kernel.php , add the following entry in $routeMiddleware array:app/Http/kernel.php中,在$routeMiddleware数组中添加以下条目:

     'cors' => \App\Http\Middleware\Cors::class

    (There would be other entries in the array like auth , guest etc. Also make sure you're doing this in app/Http/kernel.php because there is another kernel.php too in Laravel) (数组中还有其他条目,如authguest等。还要确保您在app/Http/kernel.php中执行此操作,因为 Laravel 中还有另一个kernel.php

  4. Add this middleware on route registration for all the routes where you want to allow access, like this:为您要允许访问的所有路由添加此中间件,如下所示:

     Route::group(['middleware' => 'cors'], function () { Route::get('getData', 'v1\MyController@getData'); Route::get('getData2', 'v1\MyController@getData2'); });
  5. In Vue front-end, make sure you call this API in mounted() function and not in data() .在 Vue 前端,请确保在mounted()函数中调用此 API,而不是在data()中。 Also make sure you use http:// or https:// with the URL in your fetch() call.还要确保在fetch()调用中使用http://https://和 URL。

Full credits to Pete Houston's blog article . Pete Houston 的博客文章的完整学分。

If you are using Express as back-end you just have to install cors and import and use it in app.use(cors());.如果你使用 Express 作为后端,你只需要安装 cors 并在 app.use(cors()); 中导入和使用它。 If it is not resolved then try switching ports.如果没有解决,请尝试切换端口。 It will surely resolve after switching ports切换端口后肯定会解决

Very easy solution (2 min to config) is to use local-ssl-proxy package from npm非常简单的解决方案(配置 2 分钟)是使用来自npm的 local-ssl-proxy

The usage is straight pretty forward:用法很简单:
1. Install the package: npm install -g local-ssl-proxy 1.安装包: npm install -g local-ssl-proxy
2. While running your local-server mask it with the local-ssl-proxy --source 9001 --target 9000 2. 在运行local-server时,使用local-ssl-proxy --source 9001 --target 9000对其进行屏蔽

PS: Replace --target 9000 with the -- "number of your port" and --source 9001 with --source "number of your port +1" PS:--target 9000替换为-- "number of your port" ,将--source 9001替换为--source "number of your port +1"

You can also set up a reverse proxy which adds the CORS headers using a self-hosted CORS Anywhere or Just CORS if you want a managed solution.如果需要托管解决方案,您还可以设置反向代理,使用自托管CORS AnywhereJust CORS添加 CORS 标头。

https://justcors.com/<id>/<your-requested-resource>
http://cors-anywhere.com/<your-requested-resource>

Solution for me was to just do it server side对我来说,解决方案就是在服务器端做

I used the C# WebClient library to get the data (in my case it was image data) and send it back to the client.我使用 C# WebClient库来获取数据(在我的情况下是图像数据)并将其发送回客户端。 There's probably something very similar in your chosen server-side language.您选择的服务器端语言中可能有一些非常相似的东西。

//Server side, api controller

[Route("api/ItemImage/GetItemImageFromURL")]
public IActionResult GetItemImageFromURL([FromQuery] string url)
{
    ItemImage image = new ItemImage();

    using(WebClient client = new WebClient()){

        image.Bytes = client.DownloadData(url);

        return Ok(image);
    }
}

You can tweak it to whatever your own use case is.您可以根据自己的用例对其进行调整。 The main point is client.DownloadData() worked without any CORS errors.要点是client.DownloadData()没有任何 CORS 错误。 Typically CORS issues are only between websites, hence it being okay to make 'cross-site' requests from your server.通常 CORS 问题仅发生在网站之间,因此可以从您的服务器发出“跨站点”请求。

Then the React fetch call is as simple as:那么 React fetch 调用就这么简单:

//React component

fetch(`api/ItemImage/GetItemImageFromURL?url=${imageURL}`, {            
        method: 'GET',
    })
    .then(resp => resp.json() as Promise<ItemImage>)
    .then(imgResponse => {

       // Do more stuff....
    )}

如果您尝试在本地主机上临时解决此问题,则可以使用此 chrome 扩展:允许 CORS Access-Control-Allow-Origin https://chrome.google.com/webstore/detail/allow-cors-access-control /lhobafahddgcelffkeicbaginigeejlf

If all the above solutions don't work, probably it's because of the file permissions as sometimes even if you have fixed the non-cors problem using Heroku or another way, it throws 403 forbidden error.如果上述所有解决方案都不起作用,可能是因为文件权限,有时即使您使用 Heroku 或其他方式修复了 non-cors 问题,它也会引发 403 禁止错误。 Set the directory/file permissions like this:像这样设置目录/文件权限:

Permissions and ownership errors A 403 Forbidden error can also be caused by incorrect ownership or permissions on your web content files and folders.权限和所有权错误 403 Forbidden 错误也可能是由于对 Web 内容文件和文件夹的所有权或权限不正确造成的。

Permissions Rule of thumb for correct permissions:权限 正确权限的经验法则:

Folders: 755文件夹:755

Static Content: 644静态内容:644

Dynamic Content: 700动态内容:700

I had a similar problem with my browser debugger saying my response.body was null but fiddler and the developer tools show it as populated that turned out to be basically the same scenario as this.我的浏览器调试器遇到了类似的问题,说我的 response.body 为空,但提琴手和开发人员工具将其显示为已填充,结果与此情况基本相同。 I was using a local Angular application hitting a Web Api service running on IISExpress.我正在使用本地 Angular 应用程序访问在 IISExpress 上运行的 Web Api 服务。 I fixed it by following the steps outlined here to find the correct applicationhost.config file to add a Access-Control-Allow-Origin header like so:我按照此处概述的步骤进行了修复,以找到正确的 applicationhost.config 文件以添加 Access-Control-Allow-Origin 标头,如下所示:

  <customHeaders>
    <clear />
    <add name="X-Powered-By" value="ASP.NET" />
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Headers" value="Content-Type" />
  </customHeaders>

The simple solution: Add the following to the very top of the php file you are requesting the data from.简单的解决方案:将以下内容添加到您从中请求数据的 php 文件的最顶部。

header("Access-Control-Allow-Origin: *");

NOTE: This method is not secure and is not recommended for a production environment!注意:此方法不安全,不建议用于生产环境!

Code Postman代码邮递员

在此处输入图像描述

Javascript Javascript

 function fnlogin(){ var url = ("http://localhost:3000/users/login"); var method =('POST'); var data = JSON.stringify({ "email": "juan.perez@gmail.com", "password": "12345" }); var xhr = new XMLHttpRequest(); xhr.withCredentials = false; // SOLUTION False not True xhr.addEventListener("readystatechange", function () { if (this.readyState === 4) { console.log(this.responseText); } }); xhr.open(method, url ,true); xhr.setRequestHeader("content-type", "application/json"); xhr.setRequestHeader("cache-control", "no-cache"); //xhr.send(data,{mode: 'no-cors'}); xhr.send(data); }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 fetch() 中使用 no-cors - How use no-cors with fetch() `fetch`,与模式`no-cors`一起使用不会调用promise.then回调 - `fetch`, work with mode `no-cors` does not call the promise.then callback 提取API模式:先不分配分配,然后分配函数变量 - Fetch API mode: no-cors assign then function variable 如何在模式为“ no-cors”的情况下使用获取API获取数据? - How to get data using fetch API with mode 'no-cors'? 使用模式为“ no-cors”的提取polyfill,响应状态= 0 - Response status = 0 using fetch polyfill with mode: 'no-cors' dn 为什么在 fetch 调用中使用 no-cors? - How a dn why to use no-cors in a fetch call? 使用javascript提取,在no-cors,cors和same-origin模式之间有所不同 - Fetch in javascript, different between mode no-cors, cors and same-origin 当我以“ no-cors”模式获取资源时,body-parser为什么会失败? - Why does body-parser fail when I fetch the resource in 'no-cors' mode? 使用带有 fetch API 的“no-cors”模式时,请求标头未按预期设置 - Request header not set as expected when using 'no-cors' mode with fetch API 如果响应不透明,如何从 url 获取数据。 模式:“no-cors”没有显示任何效果 - How to fetch the data from the url if the response coming is opaque. mode: "no-cors" is not showing any effect
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM