hgq's docs
主页
ES6-阮一峰 (opens new window)
Vue文档 (opens new window)
Axios文档 (opens new window)
Vue Router (opens new window)
Vuex文档 (opens new window)
面试题-Vue (opens new window)
面试题-JS (opens new window)

guoguoqiqi

漫不经心的向往
主页
ES6-阮一峰 (opens new window)
Vue文档 (opens new window)
Axios文档 (opens new window)
Vue Router (opens new window)
Vuex文档 (opens new window)
面试题-Vue (opens new window)
面试题-JS (opens new window)
  • HTTP状态码及其含义
  • 说一说浏览器缓存机制
  • 跨域的解决办法
  • 从输入url地址栏,发生了什么
  • 说说 HTTP1、HTTP2的区别
  • Http 和 Https区别
  • get、post区别
  • 说一说对跨域的认识
    • 说一说web中的XSS、CSRF攻击以及如何防范
    • DNS协议是什么、说说DNS完整的查询过程
    • 说一说TCP和UDP的区别
    • 说一说SPDY
    • 了解websocket协议吗
    • tcp三次握手和四次挥手
    • http1、http2、http3总结
    • 网络
    guoguoqiqi
    2022-03-02

    说一说对跨域的认识

    # 为什么会跨域

    同源策略,它规定了协议号-域名-端口号这三者必须都相同才符合同源策略。

    如下:

    image

    如有一个不相同,就会出现跨域问题,不符合同源策略导致的后果有

    1. LocalStorge、SessionStorge、Cookie等浏览器内存无法跨域访问
    2. DOM节点无法跨域操作
    3. Ajax请求无法跨域请求

    注意

    一个IP是可以注册多个不同域名的,也就是多个域名可能指向同一个IP,即使是这样,他们也不符合同源策略

    # 跨域的时机

    结论

    请求发出去到后端,后端返回数据,在浏览器接收后端数据时被浏览器的跨域报错拦下来

    image

    # 解决跨域的方案

    # 1. JSONP

    前面咱们说了,因为浏览器同源策略的存在,导致存在跨域问题,那有没有不受跨域问题所束缚的东西呢?其实是有的,以下这三个标签加载资源路径是不受束缚的

    1. script标签:<script src="加载资源路径"></script>
    2. link标签:<link herf="加载资源路径"></link>
    3. img标签:<img src="加载资源路径"></img>

    而JSONP就是利用了script的src加载不受束缚,从而可以拥有从不同的域拿到数据的能力。但是JSONP需要前端后端配合,才能实现最终的跨域获取数据。

    JSONP通俗点说就是:利用script的src去发送请求,将一个方法名callback传给后端,后端拿到这个方法名,将所需数据,通过字符串拼接成新的字符串callback(所需数据),并发送到前端,前端接收到这个字符串之后,就会自动执行方法callback(所需数据)。老规矩,先上图,再上代码。

    image

    后端代码:

    // index.js  http://127.0.0.1:8000
    
    const http = require('http');
    const urllib = require('url');
    
    const port = 8000;
    
    http.createServer(function (req, res) {
        const { query } = urllib.parse(req.url, true);
        if (query && query.callback) {
            const { name, age, callback } = query
            const person = `${name}今年${age}岁啦!!!`
            const str = `${callback}(${JSON.stringify(person)})` // 拼成callback(data)
            res.end(str);
        } else {
            res.end(JSON.stringify('没东西啊你'));
        }
    }).listen(port, function () {
        console.log('server is listening on port ' + port);
    })
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

    前端代码:

    // index.html  http://127.0.0.1:5500/index.html
    
    const jsonp = (url, params, cbName) => {
        return new Promise((resolve, reject) => {
            const script = document.createElement('script')
            window[cbName] = (data) => {
                resolve(data)
                document.body.removeChild(script)
            }
            params = { ...params, callback: cbName }
            const arr = Object.keys(params).map(key => `${key}=${params[key]}`)
            script.src = `${url}?${arr.join('&')}`
            document.body.appendChild(script)
        })
    }
    
    jsonp('http://127.0.0.1:8000', { name: 'xxx', age: 13 }, 'callback').then(data => {
        console.log(data) // xxx今年13岁啦!!!
    })
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    # 2. Cors

    Cors,全称是Cross-Origin Resource Sharing,意思是跨域资源共享,Cors一般是由后端来开启的,一旦开启,前端就可以跨域访问后端。

    为什么后端开启Cors,前端就能跨域请求后端呢?我的理解是:前端跨域访问到后端,后端开启Cors,发送Access-Control-Allow-Origin: 域名 字段到前端(其实不止一个),前端浏览器判断Access-Control-Allow-Origin的域名如果跟前端域名一样,浏览器就不会实行跨域拦截,从而解决跨域问题。

    image

    后端代码:

    // index.js  http://127.0.0.1:8000
    
    const http = require('http');
    const urllib = require('url');
    
    const port = 8000;
    
    http.createServer(function (req, res) {
        // 开启Cors
        res.writeHead(200, {
            //设置允许跨域的域名,也可设置*允许所有域名
            'Access-Control-Allow-Origin': 'http://127.0.0.1:5500',
            //跨域允许的请求方法,也可设置*允许所有方法
            "Access-Control-Allow-Methods": "DELETE,PUT,POST,GET,OPTIONS",
            //允许的header类型
            'Access-Control-Allow-Headers': 'Content-Type'
        })
        const { query: { name, age } } = urllib.parse(req.url, true);
        res.end(`${name}今年${age}岁啦!!!`);
    }).listen(port, function () {
        console.log('server is listening on port ' + port);
    })
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

    # 3. Node接口代理

    还是回到同源策略,同源策略它只是浏览器的一个策略而已,它是限制不到后端的,也就是前端-后端会被同源策略限制,但是后端-后端则不会被限制,所以可以通过Node接口代理,先访问已设置Cors的后端1,再让后端1去访问后端2获取数据到后端1,后端1再把数据传到前端

    image

    # 4. Nginx

    其实Nginx跟Node接口代理是一个道理,只不过Nginx就不需要我们自己去搭建一个中间服务

    image

    将nginx目录下的nginx.conf修改如下:

    server{    
        listen 8888;     
        server_name  127.0.0.1;      
        
        location /{        
            proxy_pass 127.0.0.1:8000;      
        }  
    }
    
    1
    2
    3
    4
    5
    6
    7
    8

    # 5. postMessage

    场景:http://127.0.0.1:5500/index.html页面中使用了iframe标签内嵌了一个http://127.0.0.1:5555/index.html的页面

    虽然这两个页面存在于一个页面中,但是需要iframe标签来嵌套才行,这两个页面之间是无法进行通信的,因为他们端口号不同,根据同源策略,他们之间存在跨域问题

    那应该怎么办呢?使用postMessage可以使这两个页面进行通信

    // http:127.0.0.1:5500/index.html
    
    <body>  
        <iframe src="http://127.0.0.1:5555/index.html" id="frame"></iframe>
    </body>
    <script>  
        document.getElementById('frame').onload = function () {      
            this.contentWindow.postMessage({ name: '林三心', age: 23 }, 'http://127.0.0.1:5555')     
            window.onmessage = function (e) {       
                console.log(e.data) // 通信内容       
           }  
        }
    </script>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // http://127.0.0.1:5555/index.html
    
    <script>     
        window.onmessage = function (e) {         
            const { data: { name, age }, origin } = e           
            e.source.postMessage(`${name}今年${age}岁啦!!!`, origin)      
        }
    </script>
    
    1
    2
    3
    4
    5
    6
    7
    8

    # 6. document.domain && iframe

    场景:a.sanxin.com/index.html 与 b.sanxin.com/index.html之间的通信

    其实上面这两个正常情况下是无法通信的,因为他们的域名不相同,属于跨域通信

    那怎么办呢?其实他们有一个共同点,那就是他们的二级域名都是sanxin.com,这使得他们可以通过document.domain && iframe的方式来通信

    image

    // http://127.0.0.1:5500/index.html
    
    <body>
        <iframe src="http://127.0.0.1:5555/index.html" id="frame"></iframe>
    </body>
    <script>
        document.domain = '127.0.0.1'
        document.getElementById('frame').onload = function () {
            console.log(this.contentWindow.data) // 通信内容
        }
    </script>
    // http://127.0.0.1:5555/index.html
    
     <script>
        // window.name="通信内容"
        document.domain = '127.0.0.1'
        var data = '通信内容';
    </script>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    # 7. WebSocket

    WebSocket是一种协议(跟http同级,都是协议),并且他可以进行跨域通信。

    image

    # 参考文章链接

    良苦用心啊!我把 7 大跨域解决方法原理画成 10 张图,做成图解! (opens new window)

    ← get、post区别 说一说web中的XSS、CSRF攻击以及如何防范→

    最近更新
    01
    vuex数据持久化怎么做
    05-22
    02
    vue的动态路由怎么配置使用
    05-22
    03
    vue权限控制一般怎么做
    05-22
    更多文章>
    Theme by Vdoing | Copyright © 2022-2022 Guoquoqiqi | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式