啥是跨域?
来自于浏览器的同源策略,当协议,域名,端口号任何一个不同时,都算作不同域,不同域之间相互请求资源,就叫作“跨域”
怎么解决跨域?
前端解决跨域 proxy
我们以vue为例,解决跨域问题。 在vue.config.js中用webpack devServer的proxy设置代理避免跨域
devServer:{
port:port,
proxy:{
//代理 /api/user/login 到 http://127.0.0.1:3000/user/login
'/api/': {
target: `http://127.0.0.1:3000/`,
changeOrigin: true
}
}
}
前端+后端 绕过跨域 jsonp
前端构造<script>
标签,请求指定url(由script
发出的get
请求不受同源策略限制),服务器返回一个函数执行语句,该函数名称通常由查询参callback的值决定,函数的参数为服务器返回的json数据。该函数在前端执行后即可获取数据
后端解决跨域
以node为例使用http-proxy-middleware
中间件
const {createProxyMiddleware} = require('http-proxy-middleware')
//代理到http://localhost:4000 真实服务器
app.use('/api', createProxyMiddleware({ target: 'http://localhost:4000', changeOrigin: true }));
CORS跨域资源共享
原理:cors是w3c规范,真正意义上解决跨域问题。它需要服务器对请求进⾏检查并对响应头做相应处理,从⽽允许跨域请求。
具体实现
- 响应简单请求:动词为get/post/head,没有自定义请求头,Content-Type是application/x-wwwform-urlencoded,multipart/form-data或text/plain之⼀,通过添加以下响应头解决:
//设置响应头:允许http://localhost:3000访问
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000')
- 假设我们添加自定义请求头x-token,使请求变为预检查请求
响应preflight请求,需要响应浏览器发出的options请求(预检请求),并根据情况设置响应头
if (method == "OPTIONS" && url == "/api/users") {
res.writeHead(200, {
//表明服务器允许 http://localhost:3000 访问api
"Access-Control-Allow-Origin": "http://localhost:3000",
//表明服务器允许请求中携带字段X-TOKEN 与Content-Type
"Access-Control-Allow-Headers": "X-Token,Content-Type",
//表明服务器允许客户端使用 POST,GET 和 OPTIONS 方法发起请求。
"Access-Control-Allow-Methods": "GET,POST,OPTION"
});
res.end();
}else if (method == "GET" && url == "/api/users") {
res.setHeader("Content-Type", "application/json");
res.setHeader("Access-Control-Allow-Origin", "http://localhost:3000",)
res.end(JSON.stringify([{ name: "tom", age: 20 }]));
如图,发起了两次请求,第一次是OPTIONS预检请求
nginx反向代理
我们可以在发布阶段配置nginx,我们看一下反向代理的工作原理:**客户端向反向代理发送请求,接着反向代理转发请求至目标服务器,并把获得的内容返回给客户端 **
配置如下:
server {
listen 80; #监听80端口
server_name localhost; #访问该域名进到nginx配置中来
location / { #访问根目录,前端页面
root html/dist; #存放页面根目录
index index.html index.htm;
try_files $uri $uri/ /index.html; #配合vue router history模式
}
location /api { #访问 /api
proxy_pass http://127.0.0.1:8081; #代理到后端接口
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}