簡體   English   中英

嘗試使用 fetch 和 pass in 模式:no-cors

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

我可以通過 Postman 到達這個端點http://catfacts-api.appspot.com/api/facts?number=99並返回JSON

此外,我正在使用 create-react-app 並希望避免設置任何服務器配置。

在我的客戶端代碼中,我試圖使用fetch來做同樣的事情,但我得到了錯誤:

請求的資源上不存在“Access-Control-Allow-Origin”header。 因此,不允許訪問來源“ http://localhost:3000 ”。 如果不透明的響應滿足您的需求,請將請求的模式設置為“no-cors”以獲取禁用 CORS 的資源。

所以我試圖將 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;
  });

有趣的是,我得到的錯誤實際上是這個 function 的語法錯誤。 我不確定我的實際fetch是否損壞,因為當我刪除 { mode: 'no-cors' } object 並為其提供不同的 URL 時,它工作得很好。

我也嘗試傳入 object { mode: 'opaque'} ,但這會從上面返回原始錯誤。

我相信我需要做的就是禁用 CORS .. 我錯過了什么?

mode: 'no-cors'不會神奇地使事情正常進行。 事實上,它讓事情變得更糟,因為它的一個效果是告訴瀏覽器, “在任何情況下都阻止我的前端 JavaScript 代碼查看響應正文和標頭的內容。” 當然,你永遠不想那樣。

來自前端 JavaScript 的跨域請求會發生什么,瀏覽器默認阻止前端代碼訪問跨域資源。 如果Access-Control-Allow-Origin在響應中,則瀏覽器會放松該阻止並允許您的代碼訪問響應。

但是,如果站點在其響應中未發送Access-Control-Allow-Origin ,則您的前端代碼無法直接訪問來自該站點的響應。 特別是,您無法通過指定mode: '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 預檢OPTIONS請求的請求,這也有效,因為在這種情況下,代理還會發回制作所需的Access-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 訪問響應,瀏覽器也不允許您從前端訪問跨域響應除非響應包含Access-Control-Allow-Origin響應標頭,否則在 Web 應用程序中運行的 JavaScript 代碼。

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”時,似乎實際上您的意思是要禁用同源策略 CORS 本身實際上是一種方法——CORS 是一種放松同源策略的方法,而不是一種限制它的方法。

但無論如何,你確實可以——在你的本地環境中——提供一個瀏覽器運行時標志來禁用安全性並不安全地運行,或者你可以在本地安裝一個瀏覽器擴展來繞過同源策略,但所做的只是只為您在本地改變情況。

無論您在本地進行什么更改,嘗試使用您的應用程序的其他任何人仍然會遇到同源策略,並且您無法為您的應用程序的其他用戶禁用該策略。

您很可能永遠不想在實踐中使用mode: 'no-cors' ,除非在一些有限的情況下,即使那樣,只有在您確切知道自己在做什么以及效果是什么的情況下。 那是因為設置mode: 'no-cors'實際上對瀏覽器說的是, “在任何情況下都阻止我的前端 JavaScript 代碼查看響應正文和標頭的內容。” 在大多數情況下,這顯然不是您想要的。


至於您考慮使用mode: 'no-cors' ,請參閱哪些限制適用於不透明響應? 詳情。 它的要點是:

  • 在有限的情況下,當您使用 JavaScript 將來自另一個來源的內容放入<script><link rel=stylesheet><img><video><audio><object><embed><iframe>元素(之所以有效,是因為它們允許跨域嵌入資源)——但出於某種原因,您不想/不能僅通過讓文檔的標記使用資源 URL 作為元素的hrefsrc屬性。

  • 當您想要對資源做的唯一事情就是緩存它時。 正如在哪些限制適用於不透明響應中所提到的那樣? ,在實踐中,當您使用 Service Worker 時,相關的 API 就是Cache Storage API

但即使在那些有限的情況下,也有一些重要的問題需要注意; 請參閱哪些限制適用於不透明響應? 詳情。


我也嘗試過傳入對象{ mode: 'opaque'}

沒有'opaque'請求模式—— opaque只是響應的一個屬性,瀏覽器在以no-cors模式發送的請求的響應上設置該不透明屬性。

但順便說一句,不透明這個詞是一個非常明確的信號,表明您最終得到的響應的性質:“不透明”意味着您無法看到它的任何細節; 它阻止你看到。

所以如果你像我一樣在 localhost 上開發一個網站,你試圖從 Laravel API 獲取數據並在你的 Vue 前端使用它,你看到了這個問題,這就是我解決它的方法:

  1. 在你的 Laravel 項目中,運行命令php artisan make:middleware Cors 這將為您創建app/Http/Middleware/Cors.php
  2. Cors.phphandles函數中添加以下代碼:

     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

    (數組中還有其他條目,如authguest等。還要確保您在app/Http/kernel.php中執行此操作,因為 Laravel 中還有另一個kernel.php

  4. 為您要允許訪問的所有路由添加此中間件,如下所示:

     Route::group(['middleware' => 'cors'], function () { Route::get('getData', 'v1\MyController@getData'); Route::get('getData2', 'v1\MyController@getData2'); });
  5. 在 Vue 前端,請確保在mounted()函數中調用此 API,而不是在data()中。 還要確保在fetch()調用中使用http://https://和 URL。

Pete Houston 的博客文章的完整學分。

如果你使用 Express 作為后端,你只需要安裝 cors 並在 app.use(cors()); 中導入和使用它。 如果沒有解決,請嘗試切換端口。 切換端口后肯定會解決

非常簡單的解決方案(配置 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"

如果需要托管解決方案,您還可以設置反向代理,使用自托管CORS AnywhereJust CORS添加 CORS 標頭。

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

對我來說,解決方案就是在服務器端做

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

如果您嘗試在本地主機上臨時解決此問題,則可以使用此 chrome 擴展:允許 CORS Access-Control-Allow-Origin https://chrome.google.com/webstore/detail/allow-cors-access-control /lhobafahddgcelffkeicbaginigeejlf

如果上述所有解決方案都不起作用,可能是因為文件權限,有時即使您使用 Heroku 或其他方式修復了 non-cors 問題,它也會引發 403 禁止錯誤。 像這樣設置目錄/文件權限:

權限和所有權錯誤 403 Forbidden 錯誤也可能是由於對 Web 內容文件和文件夾的所有權或權限不正確造成的。

權限 正確權限的經驗法則:

文件夾:755

靜態內容:644

動態內容:700

我的瀏覽器調試器遇到了類似的問題,說我的 response.body 為空,但提琴手和開發人員工具將其顯示為已填充,結果與此情況基本相同。 我正在使用本地 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>

簡單的解決方案:將以下內容添加到您從中請求數據的 php 文件的最頂部。

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

注意:此方法不安全,不建議用於生產環境!

代碼郵遞員

在此處輸入圖像描述

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM