Đang cố gắng sử dụng tìm nạp và vượt qua trong chế độ: không có cors


166

Tôi có thể đạt điểm cuối này, http://catfacts-api.appspot.com/api/facts?number=99thông qua Postman và nó sẽ trả vềJSON

Ngoài ra, tôi đang sử dụng ứng dụng tạo phản ứng và muốn tránh thiết lập bất kỳ cấu hình máy chủ nào.

Trong mã khách hàng của tôi, tôi đang cố gắng sử dụng fetchđể làm điều tương tự, nhưng tôi gặp lỗi:

Không có tiêu đề 'Kiểm soát truy cập-Cho phép-Xuất xứ' trên tài nguyên được yêu cầu. Do đó, nguồn gốc ' http: // localhost: 3000 ' không được phép truy cập. Nếu một phản hồi mờ phục vụ nhu cầu của bạn, hãy đặt chế độ của yêu cầu thành 'no-cors' để lấy tài nguyên với CORS bị vô hiệu hóa.

Vì vậy, tôi đang cố gắng truyền vào một đối tượng, đến Fetch của tôi sẽ vô hiệu hóa CORS, như vậy:

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;
  });

Điều thú vị là lỗi tôi nhận được thực sự là một lỗi cú pháp với chức năng này. Tôi không chắc chắn thực tế của tôi đã fetchbị hỏng, bởi vì khi tôi xóa đối tượng {mode: 'no-cors'} và cung cấp cho nó một URL khác, nó hoạt động tốt.

Tôi cũng đã cố gắng vượt qua trong đối tượng { mode: 'opaque'}, nhưng điều này trả về lỗi ban đầu từ phía trên.

Tôi tin tất cả những gì tôi cần làm là vô hiệu hóa CORS .. Tôi còn thiếu gì?

Câu trả lời:


290

mode: 'no-cors'sẽ không làm cho mọi thứ hoạt động một cách kỳ diệu. Trong thực tế, nó làm cho mọi thứ tồi tệ hơn, bởi vì một tác động của nó là nói với các trình duyệt, chặn Chặn mã JavaScript của tôi để xem nội dung của nội dung phản hồi và các tiêu đề trong mọi trường hợp. Tất nhiên bạn gần như không bao giờ muốn điều đó.

Điều xảy ra với các yêu cầu nguồn gốc chéo từ JavaScript frontend là các trình duyệt theo mặc định chặn mã giao diện truy cập nguồn gốc chéo. Nếu Access-Control-Allow-Originlà trong một phản hồi, thì các trình duyệt sẽ thư giãn việc chặn đó và cho phép mã của bạn truy cập vào phản hồi.

Nhưng nếu một trang web không gửi Access-Control-Allow-Originphản hồi của nó, mã frontend của bạn không thể truy cập trực tiếp các phản hồi từ trang web đó. Cụ thể, bạn không thể sửa nó bằng cách chỉ định mode: 'no-cors'(thực tế là sẽ đảm bảo mã frontend của bạn không thể truy cập nội dung phản hồi).

Tuy nhiên, một điều sẽ hoạt động: nếu bạn gửi yêu cầu của mình thông qua proxy CORS , như thế này:

var proxyUrl = 'https://cors-anywhere.herokuapp.com/',
    targetUrl = 'http://catfacts-api.appspot.com/api/facts?number=99'
fetch(proxyUrl + targetUrl)
  .then(blob => blob.json())
  .then(data => {
    console.table(data);
    document.querySelector("pre").innerHTML = JSON.stringify(data, null, 2);
    return data;
  })
  .catch(e => {
    console.log(e);
    return e;
  });
<pre></pre>

Lưu ý: nếu khi bạn cố gắng sử dụng https://cors-anywhere.herokuapp.com, bạn sẽ thấy nó bị hỏng , bạn cũng có thể dễ dàng triển khai proxy của riêng mình cho Heroku chỉ trong 2-3 phút, với 5 lệnh:

git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master

Sau khi chạy các lệnh đó, bạn sẽ kết thúc với máy chủ CORS Anywhere của mình đang chạy tại, ví dụ: https://cryptic-headland-94862.herokuapp.com/ . Vì vậy, thay vì tiền tố URL yêu cầu của bạn với https://cors-anywhere.herokuapp.com, tiền tố thay vào đó bằng URL cho ví dụ của riêng bạn; ví dụ: https://cryptic-headland-94862.herokuapp.com/https://example.com .


Tôi có thể đạt điểm cuối này, http://catfacts-api.appspot.com/api/facts?number=99thông qua Postman

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS giải thích lý do tại sao mặc dù bạn có thể truy cập phản hồi với Postman, các trình duyệt sẽ không cho phép bạn truy cập nguồn gốc phản hồi từ frontend Mã JavaScript chạy trong ứng dụng web trừ khi phản hồi bao gồm Access-Control-Allow-Origintiêu đề phản hồi.

http://catfacts-api.appspot.com/api/facts?number=99 không có Access-Control-Allow-Origintiêu đề phản hồi, vì vậy không có cách nào mã frontend của bạn có thể truy cập vào nguồn gốc phản hồi.

Trình duyệt của bạn có thể nhận được phản hồi tốt và bạn có thể thấy nó trong Postman và thậm chí trong trình duyệt devtools, nhưng điều đó không có nghĩa là trình duyệt sẽ hiển thị mã đó. Họ sẽ không, bởi vì nó không có Access-Control-Allow-Origintiêu đề phản hồi. Vì vậy, thay vào đó bạn phải sử dụng proxy để có được nó.

Proxy thực hiện yêu cầu đến trang web đó, nhận phản hồi, thêm Access-Control-Allow-Origintiêu đề phản hồi và bất kỳ tiêu đề CORS nào khác cần thiết, sau đó chuyển lại mã đó đến mã yêu cầu của bạn. Và phản hồi với Access-Control-Allow-Origintiêu đề được thêm vào là những gì trình duyệt nhìn thấy, vì vậy trình duyệt cho phép mã frontend của bạn thực sự truy cập vào phản hồi.


Vì vậy, tôi đang cố gắng truyền vào một đối tượng, đến Fetch của tôi sẽ vô hiệu hóa CORS

Bạn không muốn làm điều đó. Để rõ ràng, khi bạn nói rằng bạn muốn vô hiệu hóa CORS, có vẻ như bạn thực sự muốn nói là bạn muốn vô hiệu hóa chính sách cùng nguồn gốc . Bản thân CORS thực sự là một cách để làm điều đó - CORS là một cách để nới lỏng chính sách cùng nguồn gốc, không phải là một cách để hạn chế nó.

Nhưng dù sao, đó là sự thật bạn có thể - chỉ trong môi trường địa phương của bạn - làm những việc như đưa cờ thời gian chạy trình duyệt của bạn để vô hiệu hóa bảo mật và chạy không an toàn hoặc bạn có thể cài đặt tiện ích mở rộng trình duyệt cục bộ để khắc phục chính sách cùng nguồn gốc, nhưng tất cả chỉ có vậy là thay đổi tình hình chỉ cho bạn tại địa phương.

Bất kể bạn thay đổi cục bộ là gì, bất kỳ ai khác đang cố gắng sử dụng ứng dụng của bạn vẫn sẽ chạy theo chính sách cùng nguồn gốc và không có cách nào bạn có thể vô hiệu hóa điều đó cho những người dùng khác trong ứng dụng của bạn.

Bạn rất có thể không bao giờ muốn sử dụng mode: 'no-cors'trong thực tế ngoại trừ trong một vài trường hợp hạn chế và thậm chí chỉ khi bạn biết chính xác những gì bạn đang làm và những tác động là gì. Đó là bởi vì cài đặt mode: 'no-cors'thực sự nói với trình duyệt là gì, chặn Chặn mã JavaScript của tôi để xem xét nội dung của nội dung phản hồi và các tiêu đề trong mọi trường hợp. Trong hầu hết các trường hợp đó rõ ràng không phải là điều bạn muốn.


Theo như các trường hợp khi bạn sẽ muốn xem xét sử dụng mode: 'no-cors', xem câu trả lời tại gì hạn chế áp dụng đối với phản ứng đục? để biết chi tiết. Ý chính của nó là các trường hợp:

  • Trong trường hợp hạn chế khi bạn đang sử dụng JavaScript để tạo ra một nguồn lực từ nguồn gốc khác nội dung của một <script>, <link rel=stylesheet>, <img>, <video>, <audio>, <object>, <embed>, hoặc <iframe>yếu tố (trong đó hoạt động vì nhúng tài nguyên chéo gốc được phép đối với những người) - nhưng vì một lý do bạn không muốn hoặc không thể làm điều đó chỉ bằng cách đánh dấu tài liệu sử dụng URL tài nguyên làm thuộc tính hrefhoặc srccho phần tử.

  • Khi điều duy nhất bạn muốn làm với một tài nguyên là lưu trữ nó. Như được đề cập trong câu trả lời tại Những hạn chế nào áp dụng cho các phản ứng mờ đục? , trong thực tế, kịch bản áp dụng là khi bạn sử dụng Công nhân dịch vụ, trong trường hợp đó API có liên quan là API lưu trữ bộ đệm .

Nhưng ngay cả trong những trường hợp hạn chế đó, vẫn có một số vấn đề quan trọng cần phải biết; xem câu trả lời tại những hạn chế nào áp dụng cho các phản ứng mờ đục? để biết chi tiết.


Tôi cũng đã cố gắng vượt qua trong đối tượng { mode: 'opaque'}

Không có mode: 'opaque'chế độ yêu cầu - opaquethay vào đó chỉ là một thuộc tính của phản hồi và các trình duyệt đặt thuộc tính mờ đó trên các phản hồi từ các yêu cầu được gửi cùng với no-corschế độ.

Nhưng thật tình cờ, từ mờ đục là một tín hiệu khá rõ ràng về bản chất của phản hồi mà bạn kết thúc với: Hồi mờ đục có nghĩa là bạn không thể nhìn thấy nó.


4
Yêu cors-anywherecách giải quyết cho các trường hợp sử dụng không đơn giản (ví dụ: tìm nạp một số dữ liệu có sẵn công khai). Câu trả lời này xác nhận sự nghi ngờ của tôi no-corskhông phổ biến vì OpaqueResponse của nó không hữu ích lắm; tức là "những trường hợp rất hạn chế"; bất cứ ai có thể giải thích cho tôi ví dụ ở đâu no-corslà hữu ích?
Hạt đậu đỏ

1
@TheRedPea Xem bản cập nhật tôi đã thực hiện cho câu trả lời tại đây (và tôi cũng đã thêm dưới dạng nhận xét cho câu hỏi của bạn tại stackoverflow.com/questions/52569895/ Lỗi )
sIDIAbarker

Tôi cần định cấu hình máy chủ Express của mình với gói CORS.js - github.com/expressjs/cors - và sau đó tôi cần xóa mode: 'no-cors'khỏi yêu cầu tìm nạp (nếu không phản hồi sẽ trống)
James L.

proxy CORS là tuyệt vời. Tôi ngạc nhiên khi nó được coi là một biện pháp "bảo mật" để chặn truy cập vào các tệp công khai. Thật là dễ dàng để đi xung quanh từ góc độ của hacker và đó chính xác là những gì nó làm. Nó thực sự chỉ là một rắc rối cho các diễn viên tốt.
Seph Reed

Tôi tạo mã của các khách hàng khác nhau sử dụng cùng một API. Tôi sử dụng nó cho đào tạo. Tôi muốn giữ mã đơn giản và cho phép người dùng chơi với nó. Tôi cần sử dụng no-cros.
profimedica

6

Vì vậy, nếu bạn giống tôi và phát triển một trang web trên localhost, nơi bạn đang cố gắng tìm nạp dữ liệu từ API của Laravel và sử dụng nó trong giao diện Vue của bạn và bạn thấy vấn đề này, đây là cách tôi giải quyết nó:

  1. Trong dự án Laravel của bạn, chạy lệnh php artisan make:middleware Cors. Điều này sẽ tạo ra app/Http/Middleware/Cors.phpcho bạn.
  2. Thêm mã sau vào bên trong handleshàm trong Cors.php:

    return $next($request)
        ->header('Access-Control-Allow-Origin', '*')
        ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  3. Trong app/Http/kernel.php, thêm các mục sau trong $routeMiddlewaremảng:

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

    (Sẽ có các mục khác trong mảng như auth, guestv.v. Ngoài ra, hãy đảm bảo rằng bạn đang thực hiện việc này app/Http/kernel.phpvì có một mục khác kernel.phptrong Laravel)

  4. Thêm phần mềm trung gian này vào đăng ký tuyến đường cho tất cả các tuyến đường mà bạn muốn cho phép truy cập, như thế này:

    Route::group(['middleware' => 'cors'], function () {
        Route::get('getData', 'v1\MyController@getData');
        Route::get('getData2', 'v1\MyController@getData2');
    });
  5. Trong Vue front-end, hãy đảm bảo bạn gọi API này trong mounted()chức năng chứ không phải trong data(). Đồng thời đảm bảo bạn sử dụng http://hoặc https://với URL trong fetch()cuộc gọi của bạn .

Tín dụng đầy đủ cho bài viết blog của Pete Houston .


3

Giải pháp đơn giản: Thêm phần sau vào phần trên cùng của tệp php mà bạn đang yêu cầu dữ liệu từ đó.

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


7
Đây là một ý tưởng rất tốt nếu bạn muốn bảo mật ít nhất có thể :).
Khỉ Heretic

những gì về hình ảnh hotlink
user889030

1

Giải pháp cho tôi là chỉ làm phía máy chủ

Tôi đã sử dụng WebClientthư viện C # để lấy dữ liệu (trong trường hợp của tôi là dữ liệu hình ảnh) và gửi lại cho khách hàng. Có lẽ có một cái gì đó rất giống với ngôn ngữ phía máy chủ đã chọn của bạn.

//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);
    }
}

Bạn có thể tinh chỉnh nó cho dù trường hợp sử dụng của riêng bạn là gì. Điểm chính được client.DownloadData()làm việc mà không có bất kỳ lỗi CORS. Thông thường, các sự cố CORS chỉ xảy ra giữa các trang web, do đó việc thực hiện các yêu cầu 'trang chéo' từ máy chủ của bạn là ổn.

Sau đó, cuộc gọi tìm nạp React đơn giản như:

//React component

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

       // Do more stuff....
    )}

1

Giải pháp rất dễ dàng (2 phút để cấu hình) là sử dụng gói proxy-ssl-proxy từnpm

Cách sử dụng khá đơn giản:
1. Cài đặt gói: npm install -g local-ssl-proxy
2. Trong khi chạy local-servermặt nạ của bạn, nó vớilocal-ssl-proxy --source 9001 --target 9000

PS: Thay thế --target 9000bằng -- "number of your port"--source 9001bằng--source "number of your port +1"


1
Tôi gặp vấn đề khi sử dụng ứng dụng của mình trong thiết bị điện thoại thực. Là giải pháp của bạn hữu ích cho trường hợp này?
Hamid Araghi

@ HamidAraghi Tôi cho rằng bây giờ, vì mục đích phát triển, máy chủ proxy sẽ chạy trên thiết bị thực sự bị ảnh hưởng bởi lỗi
volna
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.