同源策略:
- 协议相同(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; 		}
  }
  |