跨域解决方案

跨域解决方案

跨域(非同源策略请求)

同源策略:

同源策略是浏览器的一个安全限制,‘协议,域名,端口’,三个都相同即为同源 其中一个不同即为非同源,非同源下三种行为受到限制:cookie无法获取,dom无法获取,ajax请求无效

跨域:

当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域

跨域的几种解决方案:

JSONP 实现跨域

JSONP 是使用方法回调的原理,script 不存在跨域请求的限制,引入其他网页的 js,这个页面的 js 可以调用你网页的代码

缺点:JSONP 需要服务端支持,且只支持 GET 请求,安全性也不好

客户端借助 script 标签请求服务端的一个地址,服务端返回一段带有调用某个全局函数调用的 js脚本,将需要返回给客户端的数据通过参数传递给这个函数,函数中就可以得到返回的数据

客户端:(http://127.0.0.1:3000)

js 实现 JSONP 跨域:

<script>
    //定义fn函数接收服务端返回的数据
    function fn(data{
        console.log(data) //{a: 1, b: 2}
    }
</script>
<!-- 通过script的src属性,请求http://127.0.0.1:4000中的getData接口并携带callback参数,指定回调函数的名字 -->
<script src="http://127.0.0.1:4000/getData?callback=fn"></script>

jquery 封装的 ajax 实现 JSONP 跨域:

$.ajax({
   url'http://127.0.0.1:4000/getData',
    methods'get',
    dataType'jsonp'//设置执行JSONP请求
    jsonpCallback'fn'//设置回调函数名字
    successres => {
        console.log(res) //{a: 1, b: 2}
    }
})
服务端:(http://127.0.0.1:4000)
//getData接口
app.get('/getData', (req, res) => {
    let data = {
        a1,
        b2
    };
    let fn = req.query.callback;
    //调用fn函数传递data数据
    res.send(fn + '(' + JSON.stringify(data) + ')');
});

CORS 跨域资源共享

CORS(Cross-Origin Resource Sharing 跨域资源共享)是一个W3C标准,是一种网络浏览器的技术规范,服务端使用额外的 HTTP 头来告诉浏览器,让运行在一个 origin (domain) 上的 Web 应用被准许访问来自不同源服务器上的指定的资源

客户端:(http://127.0.0.1:3000)

需要配置是否携带 cookie:withCredentials: true

//原生js
var xhr = new XMLHttpRequest()
xhr.open("get","http://127.0.0.1:4000",true)
xhr.withCredentials = true;   
xhr.send()
xhr.onload = function(){
     console.log(xhr.response)  
}
//JQuery
$.ajax({  
  url : 'http://127.0.0.1:40006',  
  method'get'
  xhrFields: {  
    withCredentialstrue  
  },  
  success : function(data{  
    console.log(data);  
  }  
});  
//axios
axios('http://127.0.0.1:4000', {  
  method'get',  
  withCredentialstrue,  
}).then(data => {  
 console.log(data);
}).catch(err => {
 console.log(err);
});
服务端:(http://127.0.0.1:4000)

普通跨域请求只需服务器端设置 Access-Control-Allow-Origin

//设置响应头的中间件
app.use((req, res, next) => {
   //设置允许指定源访问(* 表示允许所有源访问,此时不能允许携带cookie)
   res.header('Access-Control-Allow-Origin''http://127.0.0.1:3000');
   //设置允许指定HTTP请求方法访问
   res.header('Access-Control-Allow-Methons''GET,POST');
   //设置允许跨域访问携带cookie(此时允许跨域访问的源不能为 *,需要指定具体的源)
   res.header('Access-Control-Allow-Credentials'true);
   //设置允许跨域访问的请求头
   res.header('Access-Control-Allow-Headers''Content_Type, Content-Length, Authorization, X-Requested-With, Accept');
   next();
})

http proxy 代理实现跨域请求

使用 webpack 的 webpack-dev-server 开发插件中的 http-proxy-middleware来实现跨域代理

客户端:
webpack.config.js:
module.exports = {
 devServer: {
  port3000,
  progresstrue,
  contentBase'./build',
  proxy: {
   '/getData': {
    //需要跨域的源
    target'http://127.0.0.1:4000',
    //允许改变请求源为target
    changeOrigintrue
   }
  }
 }
}

postMessage 实现跨源通信

postMessage 是 html5 新增的一个解决跨域的一个方法,postMessage() 方法允许来自不同源的脚本采用异步方式进行有限的通信,可以安全地实现跨文本档、多窗口、跨域消息传递

客户端:(http://127.0.0.1:3000)
//打开指定源
let open = window.open('http://127.0.0.1:4000');
//发送消息到指定源(服务端)
open.postMessage('a''http://127.0.0.1:4000');
//监听服务端发来的消息
window.addEventListener('message', funciton(event) {
    console.log(event.data) //ab
}, false)
服务端:(http://127.0.0.1:4000)
//监听客户端发来的消息
window.addEventListener('message', funciton(event) {
    console.log(event.data) //a
    //发送消息到客户端
    event.source.postMessage(event.data + 'b')
}, false)

webScoket 实现跨源通信

webSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。webSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,进行数据互相传送Socket.IO 是一个基于 webSocket 封装的库,包括了客户端的js和服务器端的nodejs,它的目标是构建可以在不同浏览器和移动设备上使用的实时应用

客户端:(http://127.0.0.1:3000)
//连接服务端
let socket = io('http://127.0.0.1:4000');
//连接成功处理
socket.on('connect'function({
    //监听服务端消息
    socket.on('message'function(msg{
        console.log(msg) //ab
    });
    //监听服务端连接关闭
    socket.on('disconnect'function({
        console.log('服务端连接关闭')
    });
});
//向服务端发送消息
socket.send('a');
服务端:(http://127.0.0.1:4000)
//监听socket连接(server是服务器创建的服务)
socket.listen(server).on('connection'function(client{
    //监听客户端消息
    client.on('message'function(msg{
     console.log(msg) //a
     //向客户端发送消息
        client.send(msg + 'b')
    });
    //监听客户端连接关闭
    client.on('disconnect'function({
        console.log('客户端连接关闭')
    });
});

window.name 实现跨域

window.name 属性可设置或返回存放窗口的名称的一个字符串,每个窗口都有独立的 window.name,窗口载入的所有页面共享一个 window.name

客户端:(http://127.0.0.1:3000)

A.html:

<iframe src="http://127.0.0.1:4000/B.html" style="display: none;"></iframe>
<script>
    let count = 0;
    iframe.onload = function({
        //判断count,只执行一次
        if(count === 0) {
            //需要先把地址指向同源
            iframe.src = 'http://127.0.0.1:3000/C.html';
            count++;
            return;
        }
        console.log(iframe.contentWindow.name) //a
    }
</script>

C.html:

//不需要代码
服务端:(http://127.0.0.1:4000)

B.html:

//定义window.name的内容
window.name = 'a'

nginx 反向代理

Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,可以实现反向代理 同源策略是浏览器遵循的标准,客户端将请求发给代理服务器,代理服务器再向后端服务器发请求就可以解决跨域的问题 配置 nginx 配置文件 nginx.conf

nginx.conf:
http{                                                         
  server{                                    
    listen  4000;                        #端口号
    server_name  http://127.0.0.1;               #主机域名
    //反向代理配置
    location /getData {
      proxy_pass http://127.0.0.1:3000;   #反向代理主机地址配置
      proxy_set_header X-real-ip $remote_addr; #设置代理请求头,将用户访问的IP记录到自己的IP地段上
      proxy_set_header Host $http_host;   #设置代理请求头,将用户访问的地址记录到自己的HOST记录上
      proxy_connect_timeout 60;     #代理连接超时时间,默认为60
      proxy_send_timeout 60;      #代理发送超时时间,默认为60
      proxy_read_timeout 60;      #代理接受超时时间,默认为60
  }
  } 
}


原文始发于微信公众号(前端24):跨域解决方案

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/217128.html

(0)
李, 若俞的头像李, 若俞

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!