[英]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 作为前缀会导致请求通过您的代理发出,其中:
https://example.com
.https://example.com
。https://example.com
.https://example.com
的响应。Access-Control-Allow-Origin
header to the response.Access-Control-Allow-Origin
标头添加到响应中。 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-Headers
和Access-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 作为元素的href
或src
属性。
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 前端使用它,你看到了这个问题,这就是我解决它的方法:
php artisan make:middleware Cors
.php artisan make:middleware Cors
。 This will create app/Http/Middleware/Cors.php
for you.app/Http/Middleware/Cors.php
。 Add the following code inside the handles
function in Cors.php
:在
Cors.php
的handles
函数中添加以下代码:
return $next($request) ->header('Access-Control-Allow-Origin', '*') ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
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) (数组中还有其他条目,如
auth
、 guest
等。还要确保您在app/Http/kernel.php
中执行此操作,因为 Laravel 中还有另一个kernel.php
)
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'); });
mounted()
function and not in data()
.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 Anywhere或Just 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.