读了阮老师的文章跨域资源共享 CORS 详解 ,想要自己实验一下 CORS 参数的各种情况,进行了如下实验。
准备工作
使用 express 模拟提供接口的服务端,使用 webpack-dev-server 模拟页面访问的客服端。
跨域请求 - 报错
express服务端,监听3000端口,代码如下:
const express = require('express');
const app = express();
app.get('/cors', (req, res) => {
res.send('get cors');
});
app.listen(3000, () => {
console.log('app listening on port 3000');
});
webpack-dev-server客户端,监听9000端口,页面代码如下:
function cors(method) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.response);
}
};
xhr.onerror = function () {
console.log('status: ' + xhr.status);
};
xhr.open(method, 'http://localhost:3000/cors');
xhr.send();
}
cors('GET');
启动两个项目后,访问页面http://localhost:9000,会看到如下错误:
浏览器出现了常见的跨域报错信息。
跨域请求 - 正常
修改服务端代码,添加 Access-Control-Allow-Origin 为 * 标识接收任意域名请求。
const express = require('express');
const app = express();
app.get('/cors', (req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.send('get cors');
});
app.listen(3000, () => {
console.log('app listening on port 3000');
});
刷新浏览器,会看到目前请求正常。
跨域请求 - 发送Cookie
目前看到的请求中是不带 Cookie 的,如果跨域请求需要发送Cookie,需要进行如下设置。
修改服务器代码
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser());
app.get('/cors', (req, res) => {
console.log(req.cookies);
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:9000');
res.setHeader('Access-Control-Allow-Credentials', true);
res.send('get cors');
});
app.listen(3000, () => {
console.log('app listening on port 3000');
});
修改客户端代码
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
这样在请求中就会带上Cookie了,注意这里在文章中提到不能设置 Access-Control-Allow-Origin 为 * ,必须指定明确的、与请求网页一致的域名。
跨域请求 - 非简单请求
非简单CORS请求,会在正式通信前,增加一次HTTP查询请求,称为"预检"请求(preflight)。预检请求用的请求方法是OPTIONS。
修改客户端代码,通过PUT方法构造非简单请求
cors('PUT');
修改服务器代码
const express = require('express');
const app = express();
app.put('/cors', (req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.send('put cors');
});
app.listen(3000, () => {
console.log('app listening on port 3000');
});
执行这样的代码会发现浏览器会发送两个请求,OPTIONS请求成功,但是PUT请求报错。
根据文章介绍,预检请求的响应头需要设置Access-Control-Allow-Origin和Access-Control-Allow-Methods等字段,表示允许CORS请求。
修改服务器代码
const express = require('express');
const app = express();
app.put('/cors', (req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.send('put cors');
});
app.options('/cors', (req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'PUT');
res.send('options cors');
});
app.listen(3000, () => {
console.log('app listening on port 3000');
});
执行代码可以看到OPTIONS和PUT请求都成功了。
实验结束。