跨域问题的9种解决方案

一 跨域问题的产生及其价值意义

   真实项目的开发中
   一个项目部署在不同服务器上
   web服务器:静态资源   kbs.game.qq.com
   data服务器:    api.sports.qq.com

   图片服务器
   - 协议
   - 域名
   - 端口号
 三者一致是同源,只要有一个不同就是跨域
 eg:
 web服务器地址:http://127.0.0.1:3000/index.html
 数据接口地址:http://127.0.0.1:4000/list    

二 JSONP跨域解决方案的底层原理

  • script
  • img
  • link
  • iframe
    不存在跨域请求的限制
    jsonp跨越图解
    前端代码:
  1. 动态创建script标签
  2. 设置src跨域地址,注意此时的回调函数也一同传到服务器
  3. script标签添加之页面
<script>
		 $("button").click(function(){
			var script=document.createElement("script");
			script.src=`http://localhost:3000?callback=show`;
			document.body.appendChild(script);
		})
		function show(weather){  //回调函数
			alert(weather);
			//document.write(weather);	
			//回调函数结尾删除标签。
			$("body>script:last").remove();  //为了节省内存每次移除创建的标签
		}
	</script>

后端处理代码

var express = require("express");

//var app = express();
//映入支持接收的请求,如何接收callback
const http = require("http");
const url = require("url");
var weather = "宝鸡 晴 18-32";
http.createServer(
  (req, res) => {
    //对请求进行处理
    var urls = url.parse(req.url, true);
    var callback = urls.query.callback;
    res.writeHead(200, {
      "Content-Type": "text/plain; charset=utf-8"
    });
    res.write(`${callback}("${weather}")`);
    res.end();
  }
).listen(3000, () => {
  console.log("Server is start!");
});

缺点:JSONP只能处理GET请求
url劫持数据不安全,安全性低下
需要前后端一起处理

CORS跨域资源共享

    服务器设置请求文件
    Access-Control-Allow-Origin
app.use((req, res, next) => {
 res.header("Access-Control-Allow-Origin", "http://localhost:8000"); 
 //=》* (支持多源,就不能允许携带cookies了)
 res.header("Access-Control-Allow-Credentials", true);
 res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length,Authorization,      Accept,X-Requested-With"); 
 res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,HEAD,OPTIONS");
 if (req.method === 'OPTIONS') { res.send('OK!'); return; } 
 next(); });
//客户端发送请求代码
axios.defaults.baseURL = 'http://127.0.0.1:8888'; 
axios.defaults.withCredentials = true; 
axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded';
axios.defaults.transformRequest = function (data) {
   if (!data) return data;
   let result = ``; 
   for (let attr in data) {
      if (!data.hasOwnProperty(attr)) break; 
       result += &${attr}=${data[attr]}; } 
        return result.substring(1); }; 
axios.interceptors.response.use(function onFulfilled(response) { 
   return response.data; },
    function onRejected(reason) { 
   return Promise.reject(reason); 
   });
    axios.defaults.validateStatus = function (status) { 
    return /^(2|3)\d{2}$/.test(status); 
    }

缺点:多源性和携带cookies不能共存

基于http proxy实现跨域请求

  • 客户端配置webpack webpack -dev- server
devServer:{
   port: 3000,
   progress:true,
   contentBase:'./build',
   proxy:{
      '/':{
        target:'http://127.0.0.1:3001',//将目标地址改为http://127.0.0.1:3001
        changeOrigin:true
     }
  }  
}

注意:vue react框架开发的项目适用

基于 post message实现跨域处理

// A页面向B页面发送请求
<iframe src="http://127.0.0.1:1002/MESSAGE/B.html"></iframe>
<script>
    let iframe = document.querySelector('iframe');
    iframe.onload = function () {
        iframe.contentWindow.postMessage('hhhh', '"http://127.0.0.1:1002/MESSAGE/B.html');//发送请求给B
    }
    window.onmessage = function (ev) {
        console.log(ev.data);
    }
    
</script>
//B页面
<script>
window.onmessage = function (ev) {
    console.log(ev.data);
    ev.source.postMessage(ev.data+'@@', ev.origin); //发送给A
}
</script>

web scoket

  • web scoket协议跨域 scoket io
//前端处理

<script src="./socket.io.js"></script>
<script>
let socket = io('http://127.0.0.1:3001/');
//=>连接成功处理
socket.on('connect', function() {
    //=>监听服务端消息
    socket.on('message', function(msg) {
        console.log('data from server:' + msg); 
    });
    //=>监听服务端关闭
    socket.on('disconnect', function() { 
        console.log('server socket has closed!');
    });
});
//=>发送消息给服务器端
socket.send("zhufengpeixun");
</script>

//服务器端处理

//=>监听socket连接:server是服务器创建的服务
socket.listen(server).on('connection', function(client) {
    //=>接收信息
    client.on('message', function(msg) {
        //=>msg客户端传递的信息
        //...
        client.send(msg+'@@');
    });
    //=>断开处理
    client.on('disconnect', function() {
        console.log('client socket has closed!');
    });
});

nginx反向代理

  • nginx反向代理 服务器进行部署,前端不需要干什么 服务器请求不存在跨域
  • 例:www.zhufengpeixun.cn -> www.zhufengpeixun.com
#proxy服务器
server {
    listen       80;
    server_name  www.zhufengpeixun.com;
    location / {
        proxy_pass   www.zhufengpeixun.cn; #反向代理
        proxy_cookie_demo www.zhufengpeixun.cn www.zhufengpeixun.com;
        add_header Access-Control-Allow-Origin www.zhufengpeixun.cn;
        add_header Access-Control-Allow-Credentials true;
    }
}

基于iframe的跨域解决方案

  • document.domin 只能实现同一个主域不同子域之间的操作
    v.qq.com —》 sprots.qq.com
<iframe src="http://school.zhufengpeixun.cn/B.html"></iframe>
<script>
    document.domain = 'zhufengpeixun.cn';
    var user = 'admin';
</script>

//子页面B http://school.zhufengpeixun.cn/B.html

<script>
    document.domain = 'zhufengpeixun.cn';
    alert(window.parent.user);
</script>
  • window.name+iframe
    必须有三个页面
  • location.hash +iframe

from 珠峰跨域公开课总结,持续更新中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值