浏览器跨域问题的总结

本文主要总结了5中常用的跨域方法,包括JSONP、CORS、Nginx、Proxy与WebSocket。在日常练手的小项目中,推荐CORS,比较方便易理解。(部分图片来源网络,如有侵权,请联系删除)

1:浏览器同源策略:

所谓同源是指:域名、协议、端口相同。核心就在于它认为自任何站点装载的信赖内容是不安全的。浏览器处于安全方面的考虑,只允许本域名下的接口交互, 不同源的客户端脚本,在没有明确授权的情况下,不能读写对方的资源。常用数据传输的方式有ajax与fetch。同源策略又分为以下两种:

  1. DOM 同源策略:禁止对不同源页面 DOM 进行操作。这里主要场景是 iframe (iframe 元素会创建包含另外一个文档的内联框架(即行内框架))跨域的情况,不同域名的 iframe 是限制互相访问的。

  2. XMLHttpRequest 同源策略:禁止使用 XHR 对象向不同源的服务器地址发起 HTTP 请求。

基于同源策略,限制了以下行为:

  • Cookie、LocalStorage 和 IndexDB 无法读取

  • DOM 和 JS 对象无法获取

  • Ajax请求发送不出去

2:跨域的定义与解决方法:

跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制。判断是否存在跨域问题很简单,这里就不进行赘述了。主要解决方法如下:

1.JSONP(过老,不常用):

JSONP是一段参数是json格式(大多数情况)的JS代码。Web页面上调用js文件时不受跨域影响(不仅如此,别人还发现凡是拥有”src”这个属性的标签都拥有跨域的能力,比如script、img、iframe)。工作原理如下:

//客户端
$.ajax({
    url:'http://127.0.0.1:8001/list',
    method:'get',
    dataType:'jsonp',
    success: res=>{
        console.log(res)
    }
});
​
//服务端
let express = require('express'),
    app = express();
app.listen(8001, _ =>{                   // ’_‘ 主要是为了占位
    console.log('ok!')
});
app.get('/list',(req,res) => {
    let {
        callback = Function.prototype  //设置默认值为一个空函数
    } = req.query;
    
    let data = {
        code:0,
        message:'test'
    };
    res.send(`${callback}(${JSON.stringify(data)    // 转义数据, 并发送给回调全局函数中
    })`);
});

优点:不受同源策略的影响 ,兼容性更好,在古老的浏览器中皆可运行,不需要XMLHttpRequest或ActiveX的支持,并且在请求完成后可以通过调用callback的方式回传结果

缺点:只支持GET请求而不支持POST、PUT、DELETE等其他类型的HTTP请求。只支持跨域HTTP请求,不能解决不同域的两个页面之间如何进行JS调用的问题。有可能存在URL劫持问题,返回木马文件,即XSS攻击

2. CORS跨域资源共享(当前流行):

CORS(Cross-Origin Resource Sharing)跨域资源共享,定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通。CORS背后的基本思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。(PS: CORS同时需要后端与浏览器的支持,只要后端实现了CORS,就实现了跨域)

注意:CORS分为简单请求与复杂请求,简单请求需满足以下条件:

1: 使用下列方法之一:GET、HEAD、POST

2:Content -Type的值仅限于下列三者之一: text/plain、multipart/form-data、application/x-www-form-urlencoded

复杂请求:

不符合以上条件的请求就肯定是复杂请求了。 复杂请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求,该请求是 option 方法的,通过该请求来知道服务端是否允许跨域请求。

1:基于Node.js的跨域设置

// 1. 客户端发送ajxa/fetch请求,首先进行axios默认配置
fetch( "http://目标资源网站", {methods:'GET'})
.then(response => response.json())
.then(data => console.log(data))
​
//2:服务器设置相关信息(需要处理options试探性请求--复杂请求)
app.use((req,res,next)=>{
    //允许哪一个源获取数据
    res.header("Access-Control-Allow-Origin","http://loaclhost:8000"); 
    //允许的客户段请求头,可以获取哪些数据
    res.header("Access-Control-Allow-Credentials","Content-Type,Content,Length,Authorization                 , Accept,X-Requested-Width");
    // 允许携带cookie
    res.setHeader('Access-Control-Allow-Credentials', true)
    //运行客户端的请求方式,预检请求,查看客户端是否存在恶意方法methods等来操控数据
    res.header("Access-Control-Alloe-Methods","PUT,POST,GET,DELETE.HEAD.OPTIONS");
    // 预检的存活时间
    res.setHeader('Access-Control-Max-Age', 6)
    // 允许返回的头
    res.setHeader('Access-Control-Expose-Headers', 'name')
​
    if(req.methods==='OPTIONS'){
        res.send('ok!');
        return;
    }
    next();
})

2:基于Python的CORS跨域实现:

def after_request(response):
    # JS前端跨域支持,使用CORS方式
    response.headers['Cache-Control'] = 'no-cache'
    response.headers['Access-Control-Allow-Origin'] = '*'
    return response

更详细的可以看阮一峰大佬的博客:跨域资源共享 CORS 详解 - 阮一峰的网络日志https://www.ruanyifeng.com/blog/2016/04/cors.html

JSONP与CORS的对比:

1: JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。

2: 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。

3: JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS)

3. Nginx反向代理跨域:

Nginx 实现跨域请和proxy原理一致,只是Nginx帮我们做了服务器转发请求,我们在请求数据时,仍然写自己的网站的请求地址,而不是实际的请求网站的地址。

流程如下:

1:将自己的前端资源部署在Nginx的HTTP服务器

2:设置网站资源根目录

3:在 nginx.conf 配置文件中,设置监听端口与proxy_pass的转发规则

前端通过代理访问数据

server{
    listen          2222;          
    server_name     localhost;      // 设置监听端口为http://localhost:2222
   
    location {
            root   /Users/relax/Desktop/9种跨域/nginx反向代理处理跨域/html;    //# 配置自己的静态网站路径,并指定网站的根目录
            index  index.html index.htm;
    }
    
    location /api{          //转发规则设置,也可使用正则表达式
        proxy_pass   http://127.0.0.1:3000
        add_header   Access-Control-Allow-Origin *;
    }
}

4. http proxy

CORS和JSONP解决跨域问题都有一个前提:需要后台的支持,Proxy可以解决这一问题。一般配合webpack和webpack-dev-server使用,具体流程如下:

  1. 自己的网站端口号是: http://127.0.0.1:12345

  2. 自己网站后台有一个 /proxy 的路由专门处理跨域数据请求.

  3. 同时,有网站提供了一个数据接口,但是端口号是:54321 -> http://127.0.0.1:54321/data.json,因为端口号不同,而产生了跨域问题

  4. 在请求data.json 时,使用/proxy路由进行代理=> http://127.0.0.1:12345/proxy?http://127.0.0.1:54321/data.json

  5. 经自己的服务器解析路径获取到真是的数据连接 http://127.0.0.1:54321/data.json

  6. 自己的服务器由于没有同源策略的限制,所以可以直接发送这个请求,并或者数据返回值.

  7. 最后经由自己的服务器返回给自己的前端浏览器

       VUE中的跨域设置

module.exports = {
    entry: {},
    module: {},
    ...
    devServer: {
        historyApiFallback: true,
        proxy: [{
            context: '/login',
            target: 'http://127.0.0.1:8080',  // 代理跨域目标接口
            changeOrigin: true,
            secure: false,  // 当代理某些https服务报错时用
            cookieDomainRewrite: '127.0.0.1'  // 可以为false,表示不修改
        }],
        noInfo: true
    }
}

5. WebSocket协议跨域

Websocket是HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。WebSocket和HTTP都是应用层协议,都基于 TCP 协议。但是 「WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据」。同时,WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了。

// 客户端
<script>
    let socket = new WebSocket('ws://localhost:3000');
    socket.onopen = function () {
      socket.send('我爱你');//向服务器发送数据
    }
    socket.onmessage = function (e) {
      console.log(e.data);//接收服务器返回的数据
    }
</script>
​
// 服务端
let WebSocket = require('ws'); //记得安装ws
let wss = new WebSocket.Server({port:3000});
wss.on('connection',function(ws) {
  ws.on('message', function (data) {
    console.log(data);
    ws.send('我不爱你')
  });
})

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值