Giới thiệu về Chia sẻ tài nguyên nhiều nguồn gốc, cách cho phép máy khách và máy chủ giao tiếp ngay cả khi chúng không ở trên cùng một miền
Một ứng dụng JavaScript chạy trong trình duyệt thường chỉ có thể truy cập các tài nguyên HTTP trên cùng một miền (nguồn gốc) phân phát nó.
Tải hình ảnh hoặc tập lệnh / kiểu luôn hoạt động, nhưngXHRvàTìm nạpcác cuộc gọi đến máy chủ khác sẽ không thành công, trừ khi máy chủ đó thực hiện một cách để cho phép kết nối đó.
Cách này được gọi là CORS,Chia sẻ tài nguyên đa nguồn gốc.
Cũng đang tải Phông chữ Web bằng@font-face
có chính sách cùng nguồn gốc theo mặc định và những thứ khác ít phổ biến hơn (như kết cấu WebGL vàdrawImage
tài nguyên được tải trong Canvas API).
Một điều rất quan trọng cần CORS làMô-đun ES, được giới thiệu gần đây trong các trình duyệt hiện đại.
Nếu bạn không thiết lập chính sách CORStrên máy chủcho phép cung cấp nguồn gốc của bên thứ ba, yêu cầu sẽ không thành công.
Tìm nạp ví dụ:
Ví dụ XHR:
Tài nguyên Cross-Origin không thành công nếu đó là:
- khác nhaumiền
- khác nhautên miền phụ
- khác nhauHải cảng
- khác nhaugiao thức
và nó ở đó để bảo mật cho bạn, để ngăn người dùng độc hại khai thácNền tảng web.
Nhưng nếu bạn kiểm soát cả máy chủ và máy khách, bạn có tất cả các lý do chính đáng để cho phép họ nói chuyện với nhau.
Làm sao?
Nó phụ thuộc vào ngăn xếp phía máy chủ của bạn.
Hỗ trợ trình duyệt
Khá tốt (về cơ bản là tất cả ngoại trừ IE <10):
Ví dụ với Express
Nếu bạn đang sử dụng Node.js và Express làm khuôn khổ, hãy sử dụngGói phần mềm trung gian CORS.
Đây là cách triển khai đơn giản của ExpressNode.jsngười phục vụ:
const express = require('express')
const app = express()
app.get(’/without-cors’, (req, res, next) => {
res.json({ msg: ‘😞 no CORS, no party!’ })
})
const server = app.listen(3000, () => {
console.log(‘Listening on port %s’, server.address().port)
})
Nếu bạn đánh/without-cors
với một yêu cầu tìm nạp từ một nguồn gốc khác, nó sẽ làm nảy sinh vấn đề CORS.
Tất cả những gì bạn cần làm để mọi thứ diễn ra suôn sẻ là yêu cầucors
gói được liên kết ở trên và chuyển nó vào dưới dạng một chức năng phần mềm trung gian cho một trình xử lý yêu cầu điểm cuối:
const express = require('express')
const cors = require('cors')
const app = express()
app.get(’/with-cors’, cors(), (req, res, next) => {
res.json({ msg: ‘WHOAH with CORS it works! 🔝 🎉’ })
})
/* the rest of the app */
Tôi đã tạo một ví dụ Glitch đơn giản, đây là mã của nó:https://glitch.com/edit/#!/flavio-cors-client.
Đây là máy chủ Node.js Express:https://glitch.com/edit/#!/flaviocopes-cors-example-express
Lưu ý cách yêu cầu không thành công vì nó không xử lý chính xác các tiêu đề CORS, như bạn có thể thấy trong bảng điều khiển Mạng, nơi bạn tìm thấy thông báo mà máy chủ đã gửi:
Chỉ cho phép các nguồn gốc cụ thể
Tuy nhiên, ví dụ này có một vấn đề: BẤT KỲ yêu cầu nào sẽ được máy chủ chấp nhận dưới dạng nguồn gốc chéo.
Như bạn có thể thấy trong bảng điều khiển Mạng, yêu cầu được chuyển có tiêu đề phản hồiaccess-control-allow-origin: *
:
Bạn cần phải định cấu hình máy chủ để chỉ cho phép một nguồn cung cấp và chặn tất cả các nguồn khác.
Sử dụng giống nhaucors
Thư viện nút, đây là cách bạn sẽ làm điều đó:
const cors = require('cors')
const corsOptions = {
origin: ‘https://yourdomain.com’,
}
app.get(’/products/:id’, cors(corsOptions), (req, res, next) => {
//…
})
Bạn cũng có thể phục vụ nhiều hơn:
const whitelist = ['http://example1.com', 'http://example2.com']
const corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
},
}
Preflight
Có một số yêu cầu được xử lý theo cách "đơn giản". Tất cảGET
yêu cầu thuộc nhóm này.
Cũng thếmột số POST
vàHEAD
yêu cầu cũng vậy.
POST
các yêu cầu cũng nằm trong nhóm này, nếu chúng đáp ứng yêu cầu sử dụng Loại-Nội dung của
application/x-www-form-urlencoded
multipart/form-data
text/plain
Tất cả các yêu cầu khác phải chạy qua giai đoạn phê duyệt trước, được gọi là preflight. Trình duyệt thực hiện việc này để xác định xem nó có quyền thực hiện một hành động hay không, bằng cách đưa ra mộtOPTIONS
yêu cầu.
Yêu cầu preflight chứa một số tiêu đề mà máy chủ sẽ sử dụng để kiểm tra quyền (các trường không liên quan bị bỏ qua):
OPTIONS /the/resource/you/request
Access-Control-Request-Method: POST
Access-Control-Request-Headers: origin, x-requested-with, accept
Origin: https://your-origin.comThe server will respond with something like this(irrelevant fields omitted):
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://your-origin.com
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETEWe checked for POST, but the server tells us we can also issue other HTTP request types for that particular resource.
Following the Node.js Express example above, the server must also handle the OPTIONS request:
var express = require('express')
var cors = require('cors')
var app = express()
//allow OPTIONS on just one resource
app.options(’/the/resource/you/request’, cors())
//allow OPTIONS on all resources
app.options(’*’, cors())
Download my free JavaScript Beginner's Handbook
More browser tutorials:
- Some useful tricks available in HTML5
- How I made a CMS-based website work offline
- The Complete Guide to Progressive Web Apps
- The Fetch API
- The Push API Guide
- The Channel Messaging API
- Service Workers Tutorial
- The Cache API Guide
- The Notification API Guide
- Dive into IndexedDB
- The Selectors API: querySelector and querySelectorAll
- Efficiently load JavaScript with defer and async
- The Document Object Model (DOM)
- The Web Storage API: local storage and session storage
- Learn how HTTP Cookies work
- The History API
- The WebP Image Format
- XMLHttpRequest (XHR)
- An in-depth SVG tutorial
- What are Data URLs
- Roadmap to learn the Web Platform
- CORS, Cross-Origin Resource Sharing
- Web Workers
- The requestAnimationFrame() guide
- What is the Doctype
- Working with the DevTools Console and the Console API
- The Speech Synthesis API
- How to wait for the DOM ready event in plain JavaScript
- How to add a class to a DOM element
- How to loop over DOM elements from querySelectorAll
- How to remove a class from a DOM element
- How to check if a DOM element has a class
- How to change a DOM node value
- How to add a click event to a list of DOM elements returned from querySelectorAll
- WebRTC, the Real Time Web API
- How to get the scroll position of an element in JavaScript
- How to replace a DOM element
- How to only accept images in an input file field
- Why use a preview version of a browser?
- The Blob Object
- The File Object
- The FileReader Object
- The FileList Object
- ArrayBuffer
- ArrayBufferView
- The URL Object
- Typed Arrays
- The DataView Object
- The BroadcastChannel API
- The Streams API
- The FormData Object
- The Navigator Object
- How to use the Geolocation API
- How to use getUserMedia()
- How to use the Drag and Drop API
- How to work with scrolling on Web Pages
- Handling forms in JavaScript
- Keyboard events
- Mouse events
- Touch events
- How to remove all children from a DOM element
- How to create an HTML attribute using vanilla Javascript
- How to check if a checkbox is checked using JavaScript?
- How to copy to the clipboard using JavaScript
- How to disable a button using JavaScript
- How to make a page editable in the browser
- How to get query string values in JavaScript with URLSearchParams
- How to remove all CSS from a page at once
- How to use insertAdjacentHTML
- Safari, warn before quitting
- How to add an image to the DOM using JavaScript
- How to reset a form
- How to use Google Fonts