Câu trả lời này bao gồm rất nhiều nền tảng, vì vậy nó được chia thành ba phần:
- Cách sử dụng proxy CORS để khắc phục các vấn đề về tiêu đề 'Không có quyền truy cập-Kiểm soát-Cho phép-Xuất xứ'
- Làm thế nào để tránh ánh sáng trước CORS
- Cách khắc phục tiêu đề của Access Access-Control-Allow-Origin không phải là vấn đề về ký tự đại diện
Cách sử dụng proxy CORS để khắc phục các vấn đề về tiêu đề 'Không có quyền truy cập-Kiểm soát-Cho phép-Xuất xứ'
Nếu bạn không kiểm soát máy chủ, mã JavaScript frontend của bạn đang gửi yêu cầu và vấn đề với phản hồi từ máy chủ đó chỉ là thiếu Access-Control-Allow-Origintiêu đề cần thiết , bạn vẫn có thể khiến mọi thứ hoạt động bằng cách thực hiện yêu cầu thông qua một Proxy CORS. Để hiển thị cách thức hoạt động, trước tiên, đây là một số mã không sử dụng proxy CORS:
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(url)
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
Lý do catchkhối bị tấn công là, trình duyệt ngăn mã đó truy cập vào phản hồi từ đó https://example.com. Và lý do trình duyệt làm điều đó là, phản hồi thiếu Access-Control-Allow-Origintiêu đề phản hồi.
Bây giờ, đây chính xác là ví dụ tương tự nhưng chỉ với một proxy CORS được thêm vào:
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(proxyurl + url) // https://cors-anywhere.herokuapp.com/https://example.com
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
Lưu ý: Nếu https://cors-anywhere.herokuapp.com không hoạt động hoặc không khả dụng khi bạn dùng thử, hãy xem bên dưới để biết cách triển khai máy chủ CORS Anywhere của bạn tại Heroku chỉ trong 2-3 phút.
Đoạn mã thứ hai ở trên có thể truy cập phản hồi thành công vì lấy URL yêu cầu và thay đổi nó thành https://cors-anywhere.herokuapp.com/https://example.com .byby chỉ cần thêm tiền tố vào URL proxy. yêu cầu được thực hiện thông qua proxy đó, sau đó:
- Chuyển tiếp yêu cầu đến
https://example.com.
- Nhận được phản hồi từ
https://example.com.
- Thêm
Access-Control-Allow-Origintiêu đề để trả lời.
- Chuyển phản hồi đó, với tiêu đề được thêm đó, trở lại mã giao diện yêu cầu.
Trình duyệt sau đó cho phép mã frontend truy cập vào phản hồi, bởi vì phản hồi đó với Access-Control-Allow-Origintiêu đề phản hồi là những gì trình duyệt nhìn thấy.
Bạn có thể dễ dàng chạy proxy của riêng mình bằng mã từ https://github.com/Rob--W/cors-anywhere/ .
Bạn cũng có thể dễ dàng triển khai proxy của riêng mình lên 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 .
Vì vậy, 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 (đôi khi sẽ như vậy), sau đó xem xét lấy tài khoản Heroku (nếu bạn chưa có) và lấy 2 hoặc 3 phút để thực hiện các bước trên để triển khai máy chủ CORS Anywhere của riêng bạn trên Heroku.
Bất kể, cho dù bạn tự chạy hay sử dụng https://cors-anywhere.herokuapp.com hoặc proxy mở khác, giải pháp này vẫn hoạt động ngay cả khi yêu cầu là một trình duyệt kích hoạt yêu cầu trình duyệt trước CORS OPTIONSvì trong trường hợp đó, proxy cũng gửi lại Access-Control-Allow-Headersvà Access-Control-Allow-Methodscác tiêu đề cần thiết để làm cho preflight thành công.
Làm thế nào để tránh ánh sáng trước CORS
Mã trong câu hỏi kích hoạt tiền tố CORS trước khi nó gửi một Authorizationtiêu đề.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_Vquests
Ngay cả khi không có điều đó, Content-Type: application/jsontiêu đề cũng sẽ kích hoạt preflight.
Điều gì có nghĩa là tiền tố của Nhật Bản: trước khi trình duyệt thử POSTmã trong câu hỏi, trước tiên, nó sẽ gửi OPTIONSyêu cầu đến máy chủ - để xác định xem máy chủ có chọn tham gia nhận nguồn gốc chéo POSTbao gồm tiêu đề Authorizationvà Content-Type: application/jsontiêu đề hay không.
Nó hoạt động khá tốt với một tập lệnh curl nhỏ - tôi lấy dữ liệu của mình.
Để kiểm tra đúng cách curl, bạn phải mô phỏng OPTIONSyêu cầu preflight mà trình duyệt gửi:
curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: Content-Type, Authorization' \
"https://the.sign_in.url"
... với https://the.sign_in.urlthay thế bởi bất cứ điều gì thực tế của bạn sign_inURL.
Phản hồi mà trình duyệt cần xem từ OPTIONSyêu cầu đó phải bao gồm các tiêu đề như thế này:
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
Nếu OPTIONSphản hồi không bao gồm các tiêu đề đó, thì trình duyệt sẽ dừng ngay tại đó và thậm chí không bao giờ cố gắng gửi POSTyêu cầu. Ngoài ra, mã trạng thái HTTP cho phản hồi phải là 2xx, thường là 200 hoặc 204. Nếu đó là bất kỳ mã trạng thái nào khác, trình duyệt sẽ dừng ngay tại đó.
Máy chủ trong câu hỏi đang trả lời OPTIONSyêu cầu bằng mã trạng thái 501, điều này rõ ràng có nghĩa là nó đang cố gắng chỉ ra rằng nó không thực hiện hỗ trợ cho OPTIONScác yêu cầu. Các máy chủ khác thường phản hồi với Phương thức 405 không được phép sử dụng mã trạng thái trong trường hợp này.
Vì vậy, bạn sẽ không bao giờ có thể thực hiện POSTcác yêu cầu trực tiếp đến máy chủ đó từ mã JavaScript frontend của mình nếu máy chủ đáp ứng OPTIONSyêu cầu đó bằng 405 hoặc 501 hoặc bất cứ điều gì khác ngoài 200 hoặc 204 hoặc nếu không đáp ứng với những điều cần thiết đó tiêu đề phản hồi.
Cách để tránh kích hoạt một ánh sáng trước cho trường hợp trong câu hỏi sẽ là:
- nếu máy chủ không yêu
Authorizationcầu tiêu đề yêu cầu mà thay vào đó (ví dụ) dựa vào dữ liệu xác thực được nhúng trong phần thân của POSTyêu cầu hoặc dưới dạng tham số truy vấn
- nếu máy chủ không yêu cầu phần
POSTthân phải có Content-Type: application/jsonloại phương tiện mà thay vào đó chấp nhận phần POSTthân như application/x-www-form-urlencodedvới một tham số có tên json(hoặc bất cứ thứ gì) có giá trị là dữ liệu JSON
Cách khắc phục tiêu đề của Access Access-Control-Allow-Origin không phải là vấn đề về ký tự đại diện
Tôi nhận được một thông báo lỗi khác:
Giá trị của tiêu đề 'Kiểm soát truy cập-Cho phép-Xuất xứ' trong phản hồi không được là ký tự đại diện '*' khi chế độ thông tin đăng nhập của yêu cầu là 'bao gồm'. Do đó, nguồn gốc ' http://127.0.0.1:3000 ' không được phép truy cập. Chế độ thông tin xác thực của các yêu cầu do XMLHttpRequest khởi xướng được kiểm soát bởi thuộc tính withCredentials.
Đối với yêu cầu bao gồm thông tin đăng nhập, các trình duyệt sẽ không cho phép mã JavaScript frontend của bạn truy cập vào phản hồi nếu giá trị của Access-Control-Allow-Origintiêu đề phản hồi là *. Thay vào đó, giá trị trong trường hợp đó phải khớp chính xác với nguồn gốc của mã frontend của bạn , http://127.0.0.1:3000.
Xem các yêu cầu được xác thực và ký tự đại diện trong bài viết Kiểm soát truy cập HTTP (CORS) MDN.
Nếu bạn kiểm soát máy chủ mà bạn đang gửi yêu cầu, thì một cách phổ biến để giải quyết trường hợp này là cấu hình máy chủ để lấy giá trị của Origintiêu đề yêu cầu và phản hồi / phản ánh lại giá trị của Access-Control-Allow-Origintiêu đề phản hồi. Ví dụ: với nginx:
add_header Access-Control-Allow-Origin $http_origin
Nhưng đó chỉ là một ví dụ; hệ thống máy chủ (web) khác cung cấp các cách tương tự với giá trị gốc echo.
Tôi đang sử dụng Chrome. Tôi cũng đã thử sử dụng Plugin Chrome CORS đó
Plugin Chrome CORS rõ ràng chỉ đơn giản là tiêm một Access-Control-Allow-Origin: *tiêu đề vào phản hồi mà trình duyệt nhìn thấy. Nếu plugin thông minh hơn, những gì nó sẽ làm là đặt giá trị của Access-Control-Allow-Origintiêu đề phản hồi giả mạo đó thành nguồn gốc thực tế của mã JavaScript frontend của bạn , http://127.0.0.1:3000.
Vì vậy, tránh sử dụng plugin đó, ngay cả để thử nghiệm. Nó chỉ là một sự xao lãng. Nếu bạn muốn kiểm tra những phản hồi bạn nhận được từ máy chủ mà không có trình duyệt lọc chúng, bạn nên sử dụng curl -Hnhư trên.
Theo như mã JavaScript frontend cho fetch(…)yêu cầu trong câu hỏi:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Loại bỏ những dòng. Các Access-Control-Allow-*tiêu đề là tiêu đề phản ứng . Bạn không bao giờ muốn gửi chúng trong một yêu cầu. Hiệu ứng duy nhất sẽ có là kích hoạt trình duyệt để thực hiện một ánh sáng trước.