尝试使用获取和传递模式:no-cors

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

提问人:dwww 提问时间:4/7/2017 最后编辑:sideshowbarkerdwww 更新时间:5/10/2023 访问量:1031837

问:

我可以通过 Postman 命中此端点,它会返回http://catfacts-api.appspot.com/api/facts?number=99JSON

此外,我正在使用 create-react-app,并希望避免设置任何服务器配置。

在我的客户端代码中,我尝试用它来做同样的事情,但我收到错误:fetch

请求的标题上不存在“Access-Control-Allow-Origin”标头 资源。因此,不允许使用原产地“http://localhost:3000” 访问。如果不透明的响应满足您的需求,请将请求的 mode 设置为“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;
  });

有趣的是,我得到的错误实际上是此函数的语法错误。我不确定我的实际情况是否损坏,因为当我删除 { mode: 'no-cors' } 对象并为其提供不同的 URL 时,它可以正常工作。fetch

我也尝试传入对象,但这会从上面返回原始错误。{ mode: 'opaque'}

我活着,我需要做的就是禁用CORS。我错过了什么?

javascript reactjs cors create-react-app fetch-api

评论

1赞 Cees Timmerman 11/20/2020
这回答了你的问题吗?处理响应 - SyntaxError:使用模式时输入意外结束:“no-cors”

答:

765赞 sideshowbarker 4/7/2017 #1

mode: 'no-cors'不会神奇地让事情顺利进行。事实上,它使事情变得更糟,因为它的一个效果是告诉浏览器,“阻止我的前端 JavaScript 代码在任何情况下都看不到响应正文和标头的内容。当然,你永远不希望那样。

来自前端 JavaScript 的跨域请求的情况是,默认情况下,浏览器会阻止前端代码跨域访问资源。如果在响应中,则浏览器会放宽该阻止,并允许代码访问响应。Access-Control-Allow-Origin

但是,如果一个站点在其响应中发送 no,则您的前端代码无法直接访问来自该站点的响应。特别是,你不能通过指定来修复它(事实上,这将确保你的前端代码无法访问响应内容)。Access-Control-Allow-Originmode: 'no-cors'

但是,有一件事起作用:如果您通过 CORS 代理发送请求

您还可以在短短 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 添加为前缀会导致通过代理发出请求,这:

  1. 将请求转发到 。https://example.com
  2. 接收来自 的响应。https://example.com
  3. 将标头添加到响应中。Access-Control-Allow-Origin
  4. 将该响应(以及添加的标头)传递回请求的前端代码。

然后,浏览器允许前端代码访问响应,因为带有响应标头的响应是浏览器看到的。Access-Control-Allow-Origin

即使请求是触发浏览器执行 CORS 预检请求的请求,这也有效,因为在这种情况下,代理还会发回使预检成功所需的 and 标头。OPTIONSAccess-Control-Allow-HeadersAccess-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

代理向该站点发出请求,获取响应,添加响应标头和所需的任何其他 CORS 标头,然后将其传递回请求代码。添加标头的响应是浏览器看到的,因此浏览器允许您的前端代码实际访问响应。Access-Control-Allow-OriginAccess-Control-Allow-Origin


所以我正在尝试将一个对象传递给我的 Fetch,这将禁用 CORS

你不想那样做。需要明确的是,当您说要“禁用 CORS”时,似乎实际上意味着要禁用同源策略。CORS 本身实际上是一种做到这一点的方法——CORS 是一种放松同源策略的方法,而不是限制它的方法。

但无论如何,在本地环境中,您确实可以做一些事情,例如提供浏览器运行时标志以禁用安全性和不安全地运行,或者您可以在本地安装浏览器扩展以绕过同源策略,但所做的只是在本地为您改变情况。

无论你在本地进行什么更改,任何尝试使用你的应用的人仍然会遇到同源策略,并且你无法为应用的其他用户禁用该策略。

很可能永远不想使用模式:除了少数有限的情况下,在实践中是“no-cors”,即使这样,也只有在你确切地知道你在做什么以及效果是什么的情况下。这是因为设置实际上对浏览器说的是,“在任何情况下都阻止我的前端 JavaScript 代码查看响应正文和标头的内容。在大多数情况下,这显然不是你想要的。mode: 'no-cors'


至于您希望考虑使用的情况,请参阅不透明响应适用哪些限制?它的要点是:mode: 'no-cors'

  • 在有限的情况下,当您使用 JavaScript 将来自另一个源的内容放入 、 、 、 或元素中时(这之所以有效,因为这些元素允许跨源嵌入资源)——但出于某种原因,您不想/不能仅仅通过让文档的标记使用资源 URL 作为元素的 or 属性来做到这一点。<script><link rel=stylesheet><img><video><audio><object><embed><iframe>hrefsrc

  • 当您唯一想对资源执行的操作是缓存它时。正如哪些限制适用于不透明响应?中所述,在实践中,使用Service Worker时,在这种情况下,相关的API是缓存存储API

但即使在这些有限的情况下,也有一些重要的问题需要注意;有关详细信息,请参阅不透明响应有哪些限制?


我也尝试传入对象{ mode: 'opaque'}

没有请求模式 — 它只是响应的一个属性,浏览器在使用模式发送的请求的响应上设置该不透明属性。'opaque'opaqueno-cors

但顺便说一句,不透明这个词是一个非常明确的信号,表明你最终得到的反应的性质:“不透明”意味着你看不到它的任何细节;它挡住了你的视线。

评论

1赞 James L. 11/9/2018
我需要使用 CORS.js 包配置我的 Express 服务器 - github.com/expressjs/cors - 然后我需要从获取请求中删除(否则响应将为空)mode: 'no-cors'
19赞 Megamind 12/23/2020
这是来自 Chrome 的一条非常愚蠢的错误消息:CORS 策略阻止了从源“localhost:8080”获取“quake.okayfun.com/maps/baseq3/index.json”的访问:请求的资源上不存在“Access-Control-Allow-Origin”标头。如果不透明响应满足您的需求,请将请求的模式设置为“no-cors”,以在禁用 CORS 的情况下获取资源。
1赞 Timo 4/25/2022
您可以预先添加常规 URL,而不是运行本地 Heroku 应用程序http://cors-anywhere.herokuapp.com
1赞 WoJ 8/24/2023
要使用的一种情况是从 SPA 到监视服务的检测信号,该服务在设定的时间内未收到呼叫时发出警报。你不关心响应:要么它温,它很好,要么它没有,监控服务将发出警报no-cors
0赞 Marina Kim 9/9/2023
我尝试了这个 Heroku cors 选项,但最终仍然出现 403 Forbidden 错误。有人可以建议吗?我正在使用 expo react native 应用程序,但需要执行 OIDC 来集成我们公司的身份/SSO
4赞 Stuart Aitken 12/23/2018 #2

对我来说,解决方案是只在服务器端做

我使用 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);
    }
}

您可以将其调整为自己的用例。要点是没有任何CORS错误。通常,CORS问题仅在网站之间发生,因此可以从服务器发出“跨站点”请求。client.DownloadData()

然后 React fetch 调用就这么简单了:

//React component

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

       // Do more stuff....
    )}

评论

0赞 patrick 11/15/2022
我在流媒体 MP3 上遇到了同样的问题。它会播放,但我无法获得字节数组(如果存在某些 CORS 条件)。现在我想我可以在 c# 中执行此操作并自己发送它,但是将字节载入并且无法使用它们真是太荒谬了。
6赞 volna 1/28/2019 #3

非常简单的解决方案(2 分钟配置)是使用 local-ssl-proxynpm

用法很简单:
1.安装软件包:
2. 在运行掩码时,使用
npm install -g local-ssl-proxylocal-serverlocal-ssl-proxy --source 9001 --target 9000

附言:替换为 和--target 9000-- "number of your port"--source 9001--source "number of your port +1"

评论

0赞 carloswm85 12/10/2021
github.com/cameronhunter/local-ssl-proxy
11赞 dotNET 7/18/2019 #4

因此,如果您像我一样在 localhost 上开发一个网站,您尝试从 Laravel API 获取数据并在您的 Vue 前端使用它,并且您看到了这个问题,以下是我解决它的方法:

  1. 在Laravel项目中,运行命令。这将为您创建。php artisan make:middleware Corsapp/Http/Middleware/Cors.php
  2. 在函数中添加以下代码:handlesCors.php

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

    ‘cors’ => \App\Http\Middleware\Cors::class
    

    (数组中还会有其他条目,如 等。还要确保你这样做,因为拉拉维尔也有另一个)authguestapp/Http/kernel.phpkernel.php

  4. 在路由注册时为要允许访问的所有路由添加此中间件,如下所示:

    Route::group(['middleware' => 'cors'], function () {
        Route::get('getData', 'v1\MyController@getData');
        Route::get('getData2', 'v1\MyController@getData2');
    });
    
  5. 在 Vue 前端中,请确保在函数中调用此 API,而不是在 中调用。此外,请确保在通话中使用 URL 或 URL。mounted()data()http://https://fetch()

完全归功于 Pete Houston 的博客文章

评论

0赞 Mazen Othman 11/5/2023
我遇到了同样的问题,我在具有不同端口的本地主机上使用 express.js 作为后端和 react.js 作为前端,所以在我看到您的答案后,尝试在节点上精细 semileler 的东西并找到 Express cors 中间件,它工作正常。
14赞 Varnit Rohilla 8/23/2020 #5

如果您使用 Express 作为后端,您只需安装并导入并在cors

app.use(cors());.

如果未解决,请尝试切换端口。 切换端口后肯定会解决

评论

2赞 velkoon 5/14/2021
我记得我大学四年级的班级,除了我们之外,没有其他小组能做到这一点——奇怪的是,这是一个简单的解决方案。这里有一个更全面的指南:stackabuse.com/handling-cors-with-node-js
1赞 Flion 6/3/2022
这仅适用于您从自己的后端请求的情况,对吗?不是来自没有设置标头的其他 API?或者您的意思是使用快速服务器作为代理?Access-Control-Allow-Origin
0赞 honam wong 11/15/2023
交换机端口动作就像一个魅力!
0赞 NAVNEET CHANDAN 6/25/2021 #6

如果上述所有解决方案都不起作用,可能是因为文件权限,因为有时即使您使用 Heroku 或其他方式修复了非 cors 问题,它也会抛出 403 禁止错误。设置目录/文件权限,如下所示:

权限和所有权错误 403 禁止访问错误也可能是由对 Web 内容文件和文件夹的所有权或权限不正确引起的。

权限 正确权限的经验法则:

文件夹:755

静态内容:644

动态内容:700

21赞 VahidKK 11/12/2021 #7

如果您尝试在本地主机上临时解决此问题,则可以使用此Chrome扩展程序:

允许 CORS 访问控制允许源

8赞 Herman Martinus 11/23/2021 #8

如果需要托管解决方案,还可以设置反向代理,该代理使用自承载的 CORS AnywhereJust CORS 添加 CORS 标头。

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

评论

0赞 Timo 4/25/2022
Cors-anywhere似乎是更好的选择,因为它是永久性的而不是暂时的,必须每天更新。justcors
0赞 gre_gor 11/4/2023
这些在生产中都没有用。
2赞 Eric 6/20/2022 #9

我的浏览器调试器也遇到了类似的问题,说我的response.body为null,但fiddler和开发人员工具将其显示为已填充,结果与此基本相同。我正在使用本地 Angular 应用程序访问在 IISExpress 上运行的 Web Api 服务。我按照此处概述的步骤找到正确的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>
0赞 Yury Vasilenko 3/14/2023 #10

就我而言,删除以前添加的内容解决了类似的问题,并且对我没有任何.headers: { 'Content-Type': 'application/json' }mode cors/no-cors

当然,我的后端在响应中添加了适当的标头。Access-Control-Allow-Origin: *

评论

0赞 Community 3/19/2023
正如目前所写的那样,你的答案尚不清楚。请编辑以添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。您可以在帮助中心找到有关如何写出好答案的更多信息。
0赞 shrekuu 3/26/2023 #11

我必须为任何提出 CORS 请求的人添加一些注释。

  • 确保两个网站都使用 HTTPS。如果要设置 withCredentials: true 并通过 cookie 发送,则 CORS 仅通过 HTTPS 工作。
  • 在服务器端配置 CORS(例如 Nginx 配置)。

下面是 Nginx 配置的示例。

server {

    # CORS block BEGIN
    add_header 'Access-Control-Allow-Origin' $http_origin;
    add_header 'Access-Control-Allow-Headers' 'x-requested-with, Content-Type, origin, authorization, accept, client-security-token';
    add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,PATCH,DELETE';
    add_header 'Access-Control-Allow-Credentials' 'true';
    # CORS block END

}
  • $http_origin只能在开发服务器上使用。将其替换为您的 生产服务器上的域。其余的,请继续搜索。

引用:

0赞 Alexandra 5/2/2023 #12

fetch(url, {mode: 'cors'})

对我有用。

基本上fetch(url, {requestParameterDataObject})

fetch JS 文档将包含有关请求参数对象中特定字段名称的更多信息。在这里,我们使用请求的 mode 字段并将其设置为 'cors'。

我的最终代码:

useEffect(() => {
        // Loading while etching API data
        setIsLoading(true);

        fetch(url, {mode: 'cors'})
            .then((response) => response.json())
            .then((data) => {
                setData(data);

                // Turn off loading flag once data comes back
                setIsLoading(false);
            });
    }, [url]);