五种跨域的解决方法

103 阅读2分钟

跨域

jsonp

  • 前端:新建script标签 通过src发送请求 返回函数调用代码: 1234 我是新增的 我也是新增的 1234--------------------- function jsonp(obj) {

    参数

    ​ obj.type = obj.type || 'get';

    ​ obj.url = obj.url || ''; let data = { ...obj.data };

    把对象转换成字符串的形式

    ​ var arr = []; for (var k in data) { arr.push(${k}=${data[k]}) } obj.url = ${obj.url}?${arr.join('&')};

    动态创建script标签

    ​ var script = document.createElement('script'); script.src = obj.url; document.body.appendChild(script) window[data.cb] = function (data) {

    window[data.cb] 是全局的 目的是把cb里的参数当做函数名,后台返回的show() 去调用 因为cb里的参数不固定,所以以data.cb的形式 相当于 function show(){} obj.success(data) 里的success会自动去调用jsonp里的success

    ​ return obj.success(data) } } jsonp({ url: 'http://localhost:3000/say', data: { wd: 'zs', cb: 'show' }, success: function (data) { console.log(data) } })

  • 后端:返回函数名调用的形式 数据通过实参传递代码: let express = require('express'); let app = express(); app.get('/say', function (req, res) { let { wd, cb } = req.query; // console.log(wd) // res.send('ok') res.end(${cb}(123)) }) app.listen(3000, () => { console.log('启动成功') })

cors

  • cors 是后端做的操作, 需要为头做一些处理,告诉浏览器一些相关信息。
  • 1.告诉浏览器哪个源可以访问我res.setHeader('Access-Control-Allow-Origin', origin)
  • 2.告诉浏览器允许携带哪个头可以访问我res.setHeader('Access-Control-Allow-Headers', 'name')
  • 3.允许哪个请求方法访问我。 浏览器默认支持get post方法 put 方法两次 第一次:试探 询问 options 第二次:发送ajax请求res.setHeader('Access-Control-Allow-Methods', 'PUT');
  • 4.是否允许携带cookieres.setHeader('Access-Control-Allow-Credentials', true);

postmessage

实现步骤:

  • 首先通过iframe标签向端口4000的b页面发送请求 但是无法传送数据 因为跨域
  • 然后获取iframe标签 利用contentWindow.postMessage向子页面b发送内容 postMessage里面有两个参数 第一个是发送的内容 第二个是规定向哪个页面发送内容
  • 接着子页面b通过window.onmessage接收到a发送的内容
  • 再接着通过e.source.postMessage向a页面发送内容响应内容
  • 最后a页面通过window.onmessagej接收到内容 存储在e.data
a页面
<body>
    <iframe src="http://localhost:4000/b.html" onload="load()" id="box"></iframe>
    <!-- <iframe src="http://localhost:4000/b.html" onload="load()" id="frames"></iframe> -->
</body>
<script>
​
    function load() {
        let frams = document.querySelector('#box')
        frams.contentWindow.postMessage('我爱你', 'http://localhost:4000/b.html');
        window.onmessage = function (e) {
            console.log(e.data);
        }
    }
b页面:
       window.onmessage = function (e) {
            console.log(e);
            e.source.postMessage('我不爱你', e.origin)
        }

name

实现步骤:

  • a页面通过iframe引入子页面c发送请求 页面可以过来但是c页面里的内容不能引入过来,因为端口号不同,所以无法请求

  • 在端口4000的c页面上挂载window.name

  • 接下来就是a页面要拿到c页面的window.name里的内容

    • 获取iframevar frame = document.querySelector('#frames')
    • 直接通过frame.contentWindow会出现跨域的问题
    • 然后让a页面指向一个同域的b页面frame.src = 'http://localhost:3000/b.html'
    • 通过frame.contentWindow拿到b页面里的name
    • 因为是c页面和b页面的window是共享的 所以b可以拿到c的name
    • 然后a就可以通过同域的b页面拿到c里面的name

<body>
    <!-- <iframe src="http://localhost:4000/c.html" onload="load()" id="frames"></iframe> -->
​
    <iframe src="http://localhost:4000/c.html" onload="load()" id="frames" frameborder="0"></iframe>
</body>
<script>
    var first = true
    function load() {
        var frame = document.querySelector('#frames')
        if (first) {
            frame.src = 'http://localhost:3000/b.html'
            first = false
        } else {
            console.log(frame.contentWindow.name);
        }
    }
c页面
    <script>
​
        window.name = '我爱你啊'
    </script>

hash

hash:是地址栏#号后面的内容 称为hash

  • a页面通过iframe向c页面发送请求加上#后面的hash内容
  • c页面收到后 a页面接收到不因为跨域
  • 然后c页面又向b页面发送请求iframe.src = 'http://127.0.0.1:3000/b.html#idontloveyou';
  • b页面与a页面同域 b页面通过window.parent.parent.location.hash找到父级的a页面
  • a页面通过window.onhashchange(只要hash发生变化就会触发这个事件)
  • 最后a就可以通过location.hash把hash内容打印出来

a页面
<body>
    <iframe src="http://localhost:4000/c.html#iloveyou" frameborder="0"></iframe>
    
</body>
<script>
    
    window.onhashchange = function () {
        console.log(location.hash)
    }  
</script>
c页面:
        // var iframe = document.createElement('iframe');
        // iframe.src = 'http://localhost:3000/b.html#idontloveyou';
        // document.body.appendChild(iframe)
b页面:
    window.parent.parent.location.hash = location.hash

\