尝试使用 fetch 和 pass in 模式:no-cors
Posted
技术标签:
【中文标题】尝试使用 fetch 和 pass in 模式:no-cors【英文标题】:Trying to use fetch and pass in mode: no-cors 【发布时间】:2017-09-01 21:27:05 【问题描述】:我可以通过 Postman 访问这个端点 http://catfacts-api.appspot.com/api/facts?number=99
,它会返回 JSON
此外,我正在使用 create-react-app 并希望避免设置任何服务器配置。
在我的客户端代码中,我尝试使用 fetch
做同样的事情,但我得到了错误:
请求中没有“Access-Control-Allow-Origin”标头 资源。因此不允许使用原点“http://localhost:3000” 使用权。如果不透明的响应满足您的需求,请设置请求的 模式为“no-cors”以获取禁用 CORS 的资源。
所以我试图将一个对象传递给我的 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;
);
有趣的是,我得到的错误实际上是这个函数的语法错误。我不确定我的实际 fetch
是否损坏,因为当我删除 mode: 'no-cors' 对象并为其提供不同的 URL 时,它可以正常工作。
我也尝试过传入对象 mode: 'opaque'
,但这会返回上面的原始错误。
我相信我需要做的就是禁用 CORS。我错过了什么?
【问题讨论】:
这能回答你的问题吗? Handle response - SyntaxError: Unexpected end of input when using mode: 'no-cors' 【参考方案1】:mode: 'no-cors'
不会神奇地让事情顺利进行。事实上,它让事情变得更糟,因为它的一个作用是告诉浏览器,“在任何情况下都阻止我的前端 javascript 代码查看响应正文和标头的内容。” .
来自前端 JavaScript 的跨域请求的情况是浏览器默认阻止前端代码访问跨域资源。如果Access-Control-Allow-Origin
在响应中,则浏览器会放松该阻止并允许您的代码访问响应。
但如果网站在其响应中未发送 Access-Control-Allow-Origin
,您的前端代码将无法直接访问来自该网站的响应。特别是,您无法通过指定 mode: 'no-cors'
来修复它(事实上,这将确保您的前端代码无法访问响应内容)。
但是, 会起作用的一件事是:如果您通过 a CORS proxy 发送请求。
您还可以在 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
运行这些命令后,您将拥有自己的 CORS Anywhere 服务器,例如,https://cryptic-headland-94862.herokuapp.com/
。
在您的请求 URL 前加上您的代理 URL;例如:
https://cryptic-headland-94862.herokuapp.com/https://example.com
将代理 URL 添加为前缀会导致请求通过您的代理发出,其中:
-
将请求转发至
https://example.com
。
收到来自https://example.com
的回复。
将Access-Control-Allow-Origin
标头添加到响应中。
将该响应连同添加的标头一起传递回请求的前端代码。
然后浏览器允许前端代码访问响应,因为带有Access-Control-Allow-Origin
响应标头的响应是浏览器看到的。
即使请求是触发浏览器执行 CORS 预检 OPTIONS
请求的请求,这也有效,因为在这种情况下,代理还会发回使预检成功所需的 Access-Control-Allow-Headers
和 Access-Control-Allow-Methods
标头。
我可以通过 Postman 到达这个端点,
http://catfacts-api.appspot.com/api/facts?number=99
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS 解释了为什么即使您可以使用 Postman 访问响应,浏览器也不允许您从 Web 应用程序中运行的前端 JavaScript 代码访问响应跨域,除非响应包含 Access-Control-Allow-Origin
响应头。
http://catfacts-api.appspot.com/api/facts?number=99 没有Access-Control-Allow-Origin
响应标头,因此您的前端代码无法跨域访问响应。
您的浏览器可以很好地获得响应,并且您可以在 Postman 甚至浏览器开发工具中看到它——但这并不意味着浏览器会将它暴露给您的代码。他们不会,因为它没有 Access-Control-Allow-Origin
响应头。所以你必须改为使用代理来获取它。
代理向该站点发出请求,获取响应,添加 Access-Control-Allow-Origin
响应标头和所需的任何其他 CORS 标头,然后将其传递回您的请求代码。添加了Access-Control-Allow-Origin
标头的响应是浏览器看到的,因此浏览器允许您的前端代码实际访问响应。
所以我试图将一个对象传递给我的 Fetch,这将禁用 CORS
你不想那样做。需要明确的是,当您说要“禁用 CORS”时,似乎实际上您的意思是要禁用 the same-origin policy。 CORS 本身实际上是一种方法——CORS 是一种放松同源策略的方法,而不是一种限制它的方法。
但无论如何,您确实可以(在您的本地环境中)提供浏览器运行时标志以禁用安全性并以不安全的方式运行,或者您可以在本地安装浏览器扩展程序以绕过同源策略,但所有这样做只是在本地为您改变这种情况。
无论您在本地进行什么更改,尝试使用您的应用的其他人仍然会遇到同源策略,并且您无法为您应用的其他用户禁用该策略。
你很可能永远不想在实践中使用mode: 'no-cors'
,除非在少数有限的情况下,即使这样,也只有在你确切知道自己在做什么以及效果如何的情况下。这是因为设置 mode: 'no-cors'
实际上对浏览器说的是,“在任何情况下都阻止我的前端 JavaScript 代码查看响应正文和标头的内容。” 在大多数情况下,这显然不是真的你想要什么。
至于您会考虑使用mode: 'no-cors'
的情况,请参阅What limitations apply to opaque responses?处的答案以了解详细信息。它的要点是:
在有限的情况下,当您使用 JavaScript 将来自另一个来源的内容放入 <script>
、<link rel=stylesheet>
、<img>
、<video>
、<audio>
、<object>
、<embed>
或<iframe>
元素(之所以有效,是因为它们允许跨域嵌入资源)——但由于某种原因,您不想/不能仅仅通过让文档的标记使用资源 URL 作为元素的href
或src
属性。
当您只想对资源进行缓存时。正如在 What limitations apply to opaque responses? 中提到的那样,实际上,当您使用 Service Worker 时,相关的 API 就是 Cache Storage API。
但即使在这些有限的情况下,也有一些重要的问题需要注意;请参阅 What limitations apply to opaque responses? 的答案以了解详细信息。
我也试过传入对象
mode: 'opaque'
没有mode: 'opaque'
请求模式——opaque
只是响应 的一个属性,浏览器会根据no-cors
模式发送的请求的响应设置该不透明属性。
但顺便说一句,不透明这个词非常明确地表明了您最终得到的响应的性质:“不透明”意味着您看不到它。
【讨论】:
喜欢cors-anywhere
用于简单的非产品用例(即获取一些公开可用的数据)的解决方法。这个答案证实了我的怀疑,no-cors
并不常见,因为它的 OpaqueResponse 不是很有用;即“非常有限的情况”;任何人都可以explain to me 示例no-cors
有用吗?
我需要使用 CORS.js 包配置我的 Express 服务器 - github.com/expressjs/cors - 然后我需要从获取请求中删除 mode: 'no-cors'
(否则响应将为空)
CORS 代理很棒。我很惊讶它被认为是一种完全阻止访问公共文件的“安全”措施。从黑客的角度来看,它是如此、如此容易绕过,而这正是它的作用。对于好演员来说,这真的只是一个麻烦。
“阻止我的前端 JavaScript 代码在任何情况下查看响应正文和标头的内容。” - 对一个明显无用的“功能”的尖锐总结。感谢您将其拼写得如此清晰;我快疯了,想弄清楚它的用途是什么……【参考方案2】:
所以如果你像我一样在 localhost 上开发一个网站,你试图从 Laravel API 获取数据并在你的 Vue 前端使用它,你看到了这个问题,这就是我解决它的方法:
-
在你的 Laravel 项目中,运行命令
php artisan make:middleware Cors
。这将为您创建app/Http/Middleware/Cors.php
。
在Cors.php
的handles
函数内添加以下代码:
return $next($request)
->header('Access-Control-Allow-Origin', '*')
->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
在app/Http/kernel.php
中,在$routeMiddleware
数组中添加以下条目:
‘cors’ => \App\Http\Middleware\Cors::class
(数组中还有其他条目,如 auth
、guest
等。还要确保你在 app/Http/kernel.php
中执行此操作,因为 Laravel 中还有另一个 kernel.php
)
为所有要允许访问的路由添加路由注册中间件,如下所示:
Route::group(['middleware' => 'cors'], function ()
Route::get('getData', 'v1\MyController@getData');
Route::get('getData2', 'v1\MyController@getData2');
);
在 Vue 前端中,确保在 mounted()
函数中调用此 API,而不是在 data()
中。还要确保在fetch()
调用中使用http://
或https://
和URL。
感谢 Pete Houston 的 blog article。
【讨论】:
【参考方案3】:如果你使用 Express 作为后端,你只需要安装 cors 并在 app.use(cors()); 中导入和使用它。 如果没有解决,请尝试切换端口。 切换端口后肯定会解决
【讨论】:
我记得我的大学四年级课程,除了我们的小组之外,没有其他小组能做到这一点——奇怪的是,这是一个简单的解决方案。以下是更详尽的指南:stackabuse.com/handling-cors-with-node-js【参考方案4】:非常简单的解决方案(配置 2 分钟)是使用来自 npm
的 local-ssl-proxy 包
用法很简单:
1。安装包:
npm install -g local-ssl-proxy
2. 在运行 local-server
时,使用 local-ssl-proxy --source 9001 --target 9000
对其进行掩码
PS:将--target 9000
替换为-- "number of your port"
,将--source 9001
替换为--source "number of your port +1"
【讨论】:
我在真实手机设备中使用我的应用程序时遇到问题。您的解决方案对这种情况有帮助吗? @HamidAraghi 我想现在,因为出于开发目的,代理服务器应该在实际受错误影响的设备上运行 github.com/cameronhunter/local-ssl-proxy【参考方案5】:对我来说,解决方案是在服务器端进行
我使用 C# WebClient
库来获取数据(在我的情况下是图像数据)并将其发送回客户端。在您选择的服务器端语言中可能存在非常相似的内容。
//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);
您可以根据自己的用例对其进行调整。要点是client.DownloadData()
没有任何CORS 错误。通常 CORS 问题仅发生在网站之间,因此可以从您的服务器发出“跨站点”请求。
那么 React 的 fetch 调用就这么简单:
//React component
fetch(`api/ItemImage/GetItemImageFromURL?url=$imageURL`,
method: 'GET',
)
.then(resp => resp.json() as Promise<ItemImage>)
.then(imgResponse =>
// Do more stuff....
)
【讨论】:
【参考方案6】:如果您尝试在本地主机上临时解决此问题,您可以使用此 chrome 扩展:允许 CORS Access-Control-Allow-Origin https://chrome.google.com/webstore/detail/allow-cors-access-control/lhobafahddgcelffkeicbaginigeejlf
【讨论】:
【参考方案7】:简单的解决方案:将以下内容添加到您从中请求数据的 php 文件的最顶部。
header("Access-Control-Allow-Origin: *");
【讨论】:
如果您想要尽可能少的安全性,这是一个非常好的主意:)。 好主意,如果您控制源。 可怕的想法。首先,它只有在您可以访问源代码的情况下才有效,而 OP 没有,并且只有在您知道安全隐患的情况下才应该这样做。 问题是关于 javascript 请求。 这个很容易被攻击【参考方案8】:如果上述所有解决方案都不起作用,可能是因为文件权限的原因,有时即使您使用 Heroku 或其他方式修复了 non-cors 问题,它也会引发 403 禁止错误。像这样设置目录/文件权限:
权限和所有权错误 403 Forbidden 错误也可能是由您的 Web 内容文件和文件夹的所有权或权限不正确引起的。
权限 正确权限的经验法则:
文件夹:755
静态内容:644
动态内容:700
【讨论】:
【参考方案9】:如果您需要托管解决方案,您还可以设置反向代理,使用自托管 CORS Anywhere 或 Just CORS 添加 CORS 标头。
https://justcors.com/<id>/<your-requested-resource>
http://cors-anywhere.com/<your-requested-resource>
【讨论】:
【参考方案10】:代码邮递员
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);
【讨论】:
以上是关于尝试使用 fetch 和 pass in 模式:no-cors的主要内容,如果未能解决你的问题,请参考以下文章
使用带有模式的 fetch API:'no-cors',无法设置请求标头
在将模式设置为“no-cors”时使用 fetch 访问 API 时出错 [重复]
Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0 using basic fetches a