跨域

跨域,就是指浏览器不能执行其他网站的脚本。它是由浏览器同源策略造成。

什么叫做同源,或者说同源的判断标准:

指的是域名、端口号、协议名都必须要相同,我们称之为同源,如果有任意一个都不一样,我们称之为不同源。

http://www.123.com/index.html 调用 http://www.123.com/server.js(非跨域)
http://www.123.com/index.html 调用 http://www.456.com/server.js(跨域,因为域名不同)
http://abc.123.com/index.html 调用 http://def.123.com/server.js(跨域,因为子域名不同)
http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.js(跨域,因为端口不同)
http://www.123.com/index.html 调用 https://www.123.com/server.js(跨域,因为协议不同)

需要注意的是,虽然 localhost 和 127.0.0.1 都是指向本机,但是仍然会被认为是跨域

 

为什么浏览器会有同源策略这个限制?

同源策略(Same origin policy)是一种来自于浏览器的约定,是一种安全策略,最早是由网景公司提出来的,现在已经成为了一种国际标准。

比如说,有一个页面,http://weibo.com 这个页面里面如果有一段 js 代码,这个 js 代码去访问 http://sina.com,由于这两个地址不同源,所以访问内容会受限,报出不同源的错误。所以可以看出,同源策略主要是对 js 代码有一个限制。

如果没有同源策略,来考虑一种情况:

假设用户先登录一个 A 网站(一家银行),接下来用户又去登陆其他网站,如果其他网站的 js 可以读取该用户的 cookie,那么就会造成用户的敏感信息泄漏。

同源策略有这么几个规定,如果非同源:

  • cookie、localstorage 和 indexdb 是无法读取

  • DOM 无法获得和修改

  • ajax 请求无法发送

跨域的解决方案:

1.通过jsonp跨域

2、document.domain + frame跨域

3、location.hash+ iframe

4、window.name + iframe跨域

5、postMessage跨域

6、跨域资源共享(CORS)

7、nginx代理跨域

8、nodejs中间件代理跨域

9、WebSocket协议跨域

  

JSONP 解决方式

JSONP 是最早的、最传统的跨域解决方案。

主要的思想在于,民间高手发现跨域只对 js 进行限制,我们浏览器在向服务器发送请求的时候,不仅仅只有执行 js 代码才会发送请求,我们浏览器在解析页面的时候,遇到一个 link、img、script,也会向服务器发送请求。

JSONP 就是利用这个限制,来绕过了浏览器的同源策略。

通过筛选,我们发现 link、img 都不合适,script 标签是最合适,请求回来的东西会被当成 js 来运行,所以,我们可以将数据悄悄包在 script 里面。

JSONP 的核心思路,是压根儿就没有发送ajax,而是创建了一个 script 标签,script 标签里面有一个 src,所以浏览器就又会向服务器发送请求

具体实现代码:

// index.html
<body>
    <button id="btn">获取后台数据</button>
    <table id="stuTab" border="0" cellspacing="0"></table>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script>
        $('#btn').click(function () {
            // 发送 ajax 请求
            // $.ajax({
            //     url: 'http://127.0.0.1:3000/stu',
            //     type: 'GET',
            //     success: function (data) {
            //         console.log(data);
            //     }
            // })

            // 使用 JSONP 来解决
            let script = document.createElement('script');
            script.setAttribute('src','http://127.0.0.1:3000/stu');
            document.getElementsByTagName('head')[0].appendChild(script);
        })

    </script>
</body>
// stu.js
router.get('/', async function(req, res, next) {
  // 调用业务层的方法
  // 服务器端也要做修改,不能单纯的只是返回数据
  // 而是要书写上对数据的操作
  res.send(`console.log([
   
])`);
});

  在 JQuery 中,简化了 JSONP 的操作,代码如下:

// index.html
$.ajax({
  url : 'http://127.0.0.1:3000/stu?callback=?',
  dataType : 'jsonp',
  success : function(data){
    console.log(data);
  }
})

// stu.js
router.get('/', async function(req, res, next) {
  // 在服务器端,所有要拿到 jquery 生成的函数
  const func = url.parse(req.url,true).query.callback;
  res.send(`${func}([
            {name: 'aaa'}
  ])`);
});

  jquery 的这种 jsonp 解决方式,有两个好处,第一个,客户端统一了写法,仍然是使用$.ajax的写法,第二个就是对数据的操作,仍然是写在客户端。

CORS 解决跨域

这个被称之为解决 ajax 跨域问题中最优雅,最简单的解决方案。

跨域问题,实际上服务器是正常返回了数据的,只不过由于浏览器的限制,导致数据被阻断了。

在国际标准组织中,为 HTTP 新增了一个标准,这个标准就称之为 CORS,翻译成中文就是“跨域资源共享标准”。

只需要在响应头里面,添加一些键值对即可。

具体代码如下:

// app.js

// 创建一个中间件,这个中间件可以往响应头里面添加键值对
function allowCrossOrigin(req,res,next){
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "X-Requested-With,Origin,Content-Type,Accept");
  res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
  res.header('Access-Control-Allow-Credentials','true');
  next();
}

// 注册中间件
app.use(allowCrossOrigin)

  

代理服务器解决跨域

代理服务器的核心思想,就是因为服务器之间不存在同源限制,所以我们可以使用同源的服务器去请求真实数据接口服务器,最后再由同源的服务器向浏览器返回数据。

代理服务器需要做请求的转发,需要安装一个中间件,http-proxy-middleware

接下来,我们需要在代理服务器中,配置 http-proxy-middleware 这个中间件,使其可以做请求转发

// 在代理服务器的 app.js 中定义转发规则

const options = {
  target : 'http://127.0.0.1:3001', // 你要进行转发,转发到哪里去
  changeOrigin : true, // 允许跨域
  // URL 的改写规则
  pathRewrite : {
    '^/api' : '/'
    // 这里意味 URL 里面有 api 的就是要改写,并且要转发的
    // http://localhost:3000/api/stu
    // 就会被改写为 http://127.0.0.1:3001/stu
  }
}

app.use('/api',proxy.createProxyMiddleware(options));

// 接下来在代理服务器的 index.html 中
// 发送请求就需要添加 api 前缀
$.ajax({
  url: 'http://localhost:3000/api/stu',
  type: 'GET',
  success: function (data) {
    console.log(data);
  }
})

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2020-12-30 23:22  瓜豆のO泡  阅读(101)  评论(0)    收藏  举报