Cross-Origin Resource Sharing (CORS) là một cơ chế sử dụng thông tin trên HTTP header để báo với trình duyệt, cho phép ứng dụng web chạy từ nhà này, có quyền truy xuất resource từ 1 nhà khác (2 thằng gọi là khác nhà khi khác tên miền, khác port, khác giao thức http và https)
Ví dụ một request cross-origin: nhà bạn ở http://domain-a.com dùng javascript gửi request bên nhà http://api.domain-b.com/data.json
Vì lý do bảo mật, trình duyệt sẽ không cho thực hiện các request cross-origin như vậy. Nghĩa là các ứng dụng web gọi API chỉ có thể sử dụng resource từ cùng nhà (same-origin policy là từ chuẩn, nếu bạn cần research thêm), trừ khi response từ nhà khác đó cho phép gọi CORS (bằng cách thêm một số thông tin trên header)
Các request có thể dùng CORS
- Gửi một network request bằng
fetch
- Web font, hoặc load
@font-face
trong CSS - WebGL texture
- Image, video
Khi config thành công trên server, server sẽ trả thêm một số thông tin trên header để trình duyệt biết và cấp phép chạy
Access-Control-Allow-Origin
Chỉ định các tên miền nào được phép truy cập, ví dụ để cho phép tất cả tên miền có thể gọi tới
Access-Control-Allow-Origin: *
Cho phép 1 tên miền cụ thể
Access-Control-Allow-Origin: https://example.com
Các kiểu request CORS
Có 2 kiểu CORS request: các request đơn thuần, và các request preflight, 2 cái này sẽ do trình duyệt xác định sử dụng cái nào, là một developer chúng ta cũng thật sự không cần quan tâm.
Request đơn thuần như GET
, POST
, HEAD
Các request được trình duyệt xếp loại đơn thuần là GET, POST, HEAD Sử dụng CORS safe -listed header Khi sử dụng Content-Type
, chỉ các giá trị sau là được cho phép application/x-www-form-urlencoded
, multipart/form-data
, text/plain
Không có các listener nào được đăng ký trên XMLHttpRequestUpload
Không sử dụng ReadableStream
Preflight request
Đơn giản là ngược lại các trường hợp ở trên thì sẽ là dạng preflight, trình duyệt sẽ gửi đi một request ở phương thức options
để xác định server có hỗ trợ ko trước khi thực sự gửi đi request chính.
Đối với loại preflight request, ngoài việc chuyển phương thức sang options
, nó sẽ set thêm một số thuộc tính trên header
Access-Control-Request-Method
: phương thức GET hay POST nên được sử dụng Access-Control-Request-Headers
: kiểu header muốn sử dụng Origin
: nơi gửi request
Ví dụ
# Request
curl -i -X OPTIONS localhost:3001/api/ping \
-H 'Access-Control-Request-Method: GET' \
-H 'Access-Control-Request-Headers: Content-Type, Accept' \
-H 'Origin: http://localhost:3000'
Chúng ta có thể tạm dịch nó ra ngôn ngữ tự nhiên là “Tao muốn thực hiện một request dạng GET với content-type
và Accept
header từ địa chỉ localhost:3000 có được ko?”
Kết quả trả về từ server sẽ cho phép trình duyệt tiến hành tiếp, hay dừng lại ở đó. Response từ server sẽ như thế này
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE
Vary: Access-Control-Request-Headers
Access-Control-Allow-Headers: Content-Type, Accept
Content-Length: 0
Date: Fri, 05 Apr 2019 11:41:08 GMT
Connection: keep-alive