[英]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 作為前綴會導致請求通過您的代理發出,其中:
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 訪問響應,瀏覽器也不允許您從前端訪問跨域響應除非響應包含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 作為元素的href
或src
屬性。
當您想要對資源做的唯一事情就是緩存它時。 正如在哪些限制適用於不透明響應中所提到的那樣? ,在實踐中,當您使用 Service Worker 時,相關的 API 就是Cache Storage API 。
但即使在那些有限的情況下,也有一些重要的問題需要注意; 請參閱哪些限制適用於不透明響應? 詳情。
我也嘗試過傳入對象
{ mode: 'opaque'}
沒有'opaque'
請求模式—— opaque
只是響應的一個屬性,瀏覽器在以no-cors
模式發送的請求的響應上設置該不透明屬性。
但順便說一句,不透明這個詞是一個非常明確的信號,表明您最終得到的響應的性質:“不透明”意味着您無法看到它的任何細節; 它阻止你看到。
所以如果你像我一樣在 localhost 上開發一個網站,你試圖從 Laravel API 獲取數據並在你的 Vue 前端使用它,你看到了這個問題,這就是我解決它的方法:
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'); });
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 Anywhere或Just 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.