同源策略:
- 协议相同(protocol)
- 主机相同(host)
- 端口相同(port)
如果不满足同源策略的网络请求就形成了跨域。
一.解决方案之 jsonp:
前端代码
1 2 3 4 5 6 7 8 9 10 11 12
| showJsonp = function (obj) { console.log(obj) }
const url = 'http://localhost:3030/getTodoJsonp?callback=showJsonp'
const scriptEle = document.createElement('script') scriptEle.setAttribute('src', url) document.body.appendChild(scriptEle) scriptEle.onload = function () { document.body.removeChild(scriptEle) }
|
服务端代码(Node Express框架)
1 2 3 4 5 6
| app.get('/getTodoJsonp', function (req, res, next) { let callback = req.query.callback let content = callback + "({'message':'测试数据'})" res.send(content) })
|
页面打印:{message: "测试数据"}
二.解决方案之CORS:
CORS (Cross-Origin Resource Sharing,跨域资源共享)是一个系统,它由一系列传输的HTTP头组成,这些HTTP头决定浏览器是否阻止前端 JavaScript 代码获取跨域请求的响应
CORS
实现起来非常方便,只需要增加一些 HTTP
头,让服务器能声明允许的访问来源
只要后端实现了 CORS
,就实现了跨域
后端代码栗子(Node Express框架)
1 2 3 4 5 6 7 8 9
| app.all('*', function (req, res, next) { res.header('Access-Control-Allow-Origin', '*') res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept') res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS') res.header('X-Powered-By', '3.2.1') res.header('Content-Type', 'application/json;charset=utf-8') next() })
|
*Access-Control-Allow-Origin
设置为其实意义不大,可以说是形同虚设,实际应用中,上线前我们会将Access-Control-Allow-Origin
值设为我们目标host
**
三.解决方案之Websocket:
Websocket 是 HTML5 的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。什么是全双工通信 ?简单来说,就是在建立连接之后,server 与 client 都能主动向对方发送或接收数据。我们这里以第三方库 ws 为例:
1 2 3 4 5 6 7 8 9 10 11 12
| const WebSocket = require('ws');
const ws = new WebSocket('ws://www.host.com/path');
ws.on('open', function open() { ws.send('something'); });
ws.on('message', function incoming(data) { console.log(data); }); ... ...
|
需要注意的是,Websocket 属于长连接,在一个页面建立多个 Websocket 连接可能会导致性能问题。
四. 解决方案之Proxy:
代理(Proxy)也称网络代理,是一种特殊的网络服务,允许一个(一般为客户端)通过这个服务与另一个网络终端(一般为服务器)进行非直接的连接。一些网关、路由器等网络设备具备网络代理功能。一般认为代理服务有利于保障网络终端的隐私或安全,防止攻击
- vue项目开发过程可以配置vue.config.js文件来设置代理允许跨域。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| module.exports = { devServer: { host: '127.0.0.1', port: 8080, open: true, proxy: { '/api': { target: "http://localhost:3030", changeOrigin: true, pathRewrite: { '^/api': "" } } } } }
axios.defaults.baseURL = '/api'
|
- 服务端实现代理请求转发
以express框架为例
1 2 3 4 5 6 7 8 9
| var express = require('express'); const proxy = require('http-proxy-middleware') const app = express() app.use(express.static(__dirname + '/')) app.use('/api', proxy({ target: 'http://localhost:4000', changeOrigin: false })); module.exports = app
|
- 通过配置
nginx
实现代理(一般用于生产环境中)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| server { listen 8088; server_name 127.0.0.1; # 主机名 gzip on; # 开启gzip压缩功能 gzip_min_length 1024; #设置最小压缩大小,单位字节 gzip_types text/plain application/x-javascript text/css application/xml; #用来指定压缩的类型,“text/html”类型总是会被压缩。 location / { root /home/exam/dist; index index.html index.htm; # 添加请求头 add_header 'Access-Control-Allow-Origin' *; add_header 'Access-Control-Allow-Credentials' 'true'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; }
location /api { include uwsgi_params; # 代理请求路径 proxy_pass http://127.0.0.1:3033/api; }
}
|