前置知识
当在 Network 发现了 CORS 字样并且请求不通的时候就是跨域了
为什么会跨域
当你的请求与你现在的网址不一样时,包括域名,协议,端口其中一项不同,浏览器就会阻止这个请求
重点 跨域是浏览器才有的问题,因为浏览器有同源政策 这里的请求并不会发出去
处理跨域的方法
JSONP
浏览器的同源政策值针对 Ajax 的,可以通过 script 标签的 src 可以请求不同源的资源,但是它只能支持 get 请求,所以想要支持所有的 http 请求,只能用 CORS 或者其他的代理方式
CORS
这种方式是需要浏览器和服务器共同支持的,浏览器的的工作都是自动完成的,开发者就更发其他 ajax 请求一样 ,浏览器发现跨域的 ajax 请求会自动添加一些头信息但是用户无感知,所以实现 CORS 请求的关键是服务器端
CORS 请求的两种方式
简单请求
满足下面两种条件的请求就属于简单请求
1) 请求方法是以下三种方法之一:
HEAD
GET
POST
2)HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
这个是兼容表单的,表单是可以发送跨域请求的,表单能发的请求,换成ajax也能发送
如果是简单请求,浏览器会在头信息里加上 origin 这个字段说明这次的请求是来着那个源,如果这个源是不在许可范围的话就会报错,在许可范围的话,浏览器就会在服务器响应头信息里加上这个字段
Access-Control-Allow-Origin: http://xxx.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8
其中 Access-Control-Allow-Origin 必须的字段,表示允许访问的域名,* 代表全部都允许
Access-Control-Allow-Credentials 可选的字段,表示是否允许发送 Cookie, 默认Cookie不包含在CORS请求中。设置为true表示允许把Cookie放在请求中一起发送,如果不允许发送把这个字段删掉就可以了。
浏览器发送Cookie到服务器端除了要服务器端配置上述允许发送的字段,前端还需要要ajax请求中打开withCredentials这是属性。如果省略有点浏览器会也会发送Cookie,如果不需要可以显示的关闭
let xhr = new XMLHttpRequest();
xhr.withCredentials = true;
注意:如果要发送cookie,Access-Control-Allow-Origin这个字段就不能配置为*,必须明确指定与请求
Access-Control-Expose-Headers 可选,CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段
非简单请求
比如请求方式是put,或content-type字段是application/json
非简单请求会在第一次http请求的时候加上预检请求, 也就是浏览器会询问当前域名是否是在服务器的许可名单中的,以及头信息,只有达到肯定回复才能发送请求,
下面是预检请求的http头信息
OPTIONS /cors HTTP/1.1
Origin: http://xxx.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
预检请求方法是OPTINS,是用来询问的,
Access-Control-Request-Method 必须的,列出请求会到的http方法
配置过程
- 下载 express 和 http-proxy-middleware
yarn add express http-proxy-middleware
- 在根目录下新建 server.js
//server.js
const express = require('express')
const next = require('next')
const { createProxyMiddleware } = require('http-proxy-middleware')
const devProxy = require('./proxy') // 引入代理文件
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app
.prepare()
.then(() => {
const server = express()
if (dev && devProxy) {
devProxy().forEach(function (proxy) {
server.use(createProxyMiddleware(proxy.context, proxy))
})
}
server.all('*', (req, res) => {
return handle(req, res)
})
server.listen(port, (err) => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
})
.catch((err) => {
console.log('An error occurred, unable to start the server')
console.log(err)
})
- 配置 proxy.js 文件
const proxy = () => {
const testServer = 'https://www.myrds.io/'
return [
{
context: ['/api'],
target: testServer,
secure: false,
changeOrigin: true,
cookieDomainRewrite: {
'*': '',
},
},
]
}
module.exports = proxy
- 相应的修改 package.json