https://github.com/beace/cors-preflight
CORS-preflight demo
https://github.com/beace/cors-preflight
cors-preflight cors-request
Last synced: about 2 months ago
JSON representation
CORS-preflight demo
- Host: GitHub
- URL: https://github.com/beace/cors-preflight
- Owner: Beace
- Created: 2019-02-18T07:18:32.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2019-02-18T07:31:19.000Z (over 6 years ago)
- Last Synced: 2025-02-05T07:31:19.610Z (4 months ago)
- Topics: cors-preflight, cors-request
- Language: JavaScript
- Size: 3.91 KB
- Stars: 1
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# CORS-preflight fetch(request)
跨域预检请求,术语为 CORS-preflight fetch 或 CORS-preflight requst。**浏览器**默认有不得跨域请求资源的限制,因此服务端往往在 response header 中加入相应的允许跨域请求的请求头,允许前端对 API 进行跨域请求。浏览器识别服务器是否允许跨域请求资源,是通过预检来完成。这篇文章,主要是来记录跨域的预检请求。## CORS-safelisted method
在服务端设置 `Access-Control-Allow-Origin` 为相应域名后,浏览器就允许按照下面这三中方法来跨域请求资源了。- GET
- HEAD
- POST也就是说,在服务端设置 `Access-Control-Allow-Origin`,资源就允许通过以上三种方法进行跨域访问。
以下示例。
```bash
touch server.js server2.js index.html
```在 `server.js` 中起一个基础的服务,为 `3000` 端口,作为服务端来提供资源
```javascript
const http = require('http');const server = http.createServer((req, res) => {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3001')
res.end('123');
});server.listen(3000, () => {
console.log('server is listening on port: 3000...');
});
```在 `server2.js` 中再起一个基础的服务,为 `3001` 端口,作为客户端渲染 `HTML`,并且请求 `3000` 端口资源。
```javascript
const http = require('http');
const fs = require('fs');const server = http.createServer((req, res) => {
const html = fs.readFileSync('./index.html', 'utf-8');
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3001')
res.end(html);
});server.listen(3001, () => {
console.log('server is listening on port: 3001...');
});
``````html
CORS-preflight
CORS-preflight
fetch('http://localhost:3000', {
method: 'POST', // OR GET HEAD
})
.then(res => res.text())
.then(data => console.log(data));
```
启动服务后进入 http://localhost:3001 可以看到,可以正常访问到 `3000` 端口的资源。

可以尝试将方法改为 `GET` 和 `HEAD`。
浏览器认为如果不是以上的安全请求方法,都会在实际请求 API 时会发出 method 为 `OPTIONS` 的预检请求。并且,对请求的方法有如下限制,以下称为 CORS 安全方法。
我们来修改下 `index.html` 中 fetch API 中的 method,这里改为 `PUT`.
```javascript
fetch('http://localhost:3000', {
method: 'POST',
})
.then(res => res.text())
.then(data => console.log(data));
```刷新页面,可以看到浏览器抛出了错误。

并且 devtool 中也可以看出事先发出了 `OPTIONS` 请求,虽然在 response 中可以看到数据,但是在代码中,获取不到实际的数据。

浏览器明确地提示,`Method PUT` 是不被允许的。或者更加明确地说,浏览器的预检(preflight)请求中没有接受到服务器返回的 `Access-Control-Allow-Methods` 中包含该方法。
修改 `server.js` 中的代码,在增加 header
```javascript
res.setHeader('Access-Control-Allow-Methods', 'PUT')
```重启服务器后可以看到,有两个请求发送,一个还是浏览器的预检请求,另外,则是 `PUT`,并成功返回了数据。

除了`PUT`之外,通常来讲,还有 `DELETE` 等方法,在实际开发中,会一并加上。
## CORS-safelisted request-header
除了 method 之外,CORS 还对请求头有一些限制。其中除以下请求头之外,其他的都会被block掉。```
accept
accept-language
conent-languate
content-type
```### Content-Type
对于 `content-type` 而言,也有以下限制。只允许以下三种。- text/plain
- multipart/form-data
- application/x-www-form-urlencoded我们来修改 `index.html` ,在 fetch 的 headers 中加入 content-type
```javascript
fetch('http://localhost:3000', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
hello: 'world'
})
})
```刷新浏览器,可以看到浏览器明确指出请求头 `content-type` 是不被允许的。

我们来修改下 `server.js` ,增加 `content-type` 为 `application/json` 的请求头。
```javascript
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
```重启服务,刷新浏览器,可以看到 `Content-Type` 为 `application/json`的可以成功接收到返回。

### Custom-header
如果是自定义的 header 呢,比如我们需要传递给服务器一个 token 来标识用户身份,修改 index.html```javascript
fetch('http://localhost:3000', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-Auth-Token': 'auth-token',
},
body: JSON.stringify({
hello: 'world'
})
})
```刷新浏览器,发现,会有上面同样的错误:不允许 `x-auth-token`。同样,修改 server.js 在,setHeader中追加
```javascript
res.setHeader('Access-Control-Allow-Headers', 'Content-Type,X-Auth-Token');
```如果以上设置太麻烦,可以通过`*`来设置。
```javascript
res.setHeader('Access-Control-Allow-Headers', '*');
```## Access-Control-Max-Age
如此重复地去发送预检请求,并不是一个好的方式。可以通过设置过期时间的方式,在保证安全的情况下在固定时间避免重复地检查。修改 `server.js` ,在 header 中设置 `Access-Control-Max-Age`
```javascript
res.setHeader('Access-Control-Max-Age', 10);
```我们约定,在10s内不再检查。重启服务,刷新浏览器。

可以看到,第一次还是进行了预检请求,10s内刷新浏览器,直接请求了 API,10s后再次刷新,预检之后发起了请求。