• 跨域解决方案


    1. cors 介绍

    cors 说的是一个机制,其实相当于一个http协议的约定,就是用一段http头部字段来开一扇后门;

    当跨域发生时,服务器本身收不到浏览器发的请求(因为被拦截了),现在服务器说我给你一扇门,但是你要符合一定的条件,只要符合条件就能通信。

    2. 原理

    当后端服务器引入了cors模块之后,前端每次向该服务器请求通信的时候,会在HTTP头部添加一个字段origin,表示请求来源地址;后端对于请求来源origin进行判断,如果符合要求(没有跨域),那么通信就会被建立,请求通过;如果请求来源origin不符合要求,则不会建立连接。使用cors模块解决跨域问题主要工作在于后端。

    浏览器本来会拦截跨域请求,但是加了cors这样的相关字段之后,浏览器就不会拦截;(在预请求中拦截)

    在HTTP返回字段中,有一个 Access-Control-Allow-Origin 字段表示能放行什么网址的请求,* 表示放行所有请求。

    3. cors 解决跨域

    express(app.js)

    const express = require('express')
    
    const log = console.log.bind(console)
    const app = express()
    
    // cors 模块用来解决跨域问题,只要声明了 cor,就说明该服务器允许跨域的访问
    const cors = require('cors')
    
    app.use(cors())
    
    app.get('/helloworld', (request, response) => {
        response.send('hello')
    })
    
    const main = () => {
        let server = app.listen(2300, () => {
            let host = server.address().address
            let port = server.address().port
    
            log(`应用实例,访问地址为 http://${host}:${port}`)
        })
    }
    
    if (require.main === module) {
        main()
    }
    

    html(crossOriginDemo.html)

    <!doctype html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>跨域demo</title>
        <style type="text/css">
            .ajaxButton {
                 100px;
                height: 50px;
                background: blue;
                color: #fff;
                display: flex;
                justify-content: center;
                align-items: center;
            }
        </style>
    </head>
    <body>
        <div class="ajaxButton">发送请求</div>
        <script>
            const log = console.log.bind(console)
    
            const ajax = (method, url, data, headers, callback) => {
                let r = new XMLHttpRequest()
                r.open(method, url, true)
    
                // 设置 headers
                Object.entries(headers).forEach(([k, v]) => {
                    r.setRequestHeader(k, v)
                })
                r.onreadystatechange = () => {
                    if (r.readyState === 4) {
                        callback(r.response)
                    }
                }
                if (method === 'POST') {
                    data = JSON.stringify(data)
                }
                r.send(data)
            }
            
            let ele = document.querySelector('.ajaxButton')
            ele.addEventListener('click', function () {
                let url = 'http://localhost:2300/helloworld'
                let method = 'GET'
                let data = {}
                let headers = {
                    'Content-Type': 'application/json',
                }
                ajax(method, url, data, headers, (r) => {
                    log('cors r is', r)
                })
            })
        </script>
    </body>
    </html>
    

    运行结果

    使用cors 模块确实能够解决跨域问题, 但是这带来了一个问题:

    后端框架中如果使用了cors 模块, 那么所有接口都默认地配置了跨域解决方案, 如果现在存在如下需求:

    1. 一部分接口是暴露给浏览器使用的, 需要配置跨域; 一部分接口是给另一台服务器使用的, 不能配置跨域;
    2. 某部分接口只想暴露给特定的origin

    此时使用cors 模块已经不能解决问题了, 需要我们手动配置跨域.

    4. 自定义HTTP 头部字段解决跨域

    有cors 的机制我们可以知道, 跨域问题的关键其实就是在于两个字段, 分别是

    1. request header 的origin 字段
    2. response header 的Access-Control-Allow-Headers 字段

    只要在options 请求, 正常请求中这些字段值为合法值, 那么就解决了跨域问题

    配置代码如下:
    express(app.js)

    const express = require('express')
    
    const log = console.log.bind(console)
    const app = express()
    
    // cors 模块用来解决跨域问题,只要声明了 cor,就说明该服务器允许跨域的访问
    // const cors = require('cors')
    
    // app.use(cors())
    
    app.get('/helloworld', (request, response) => {
        log('触发了该事件')
        response.send('hello')
    })
    
    app.get('/singlecors', (request, response) => {
        response.set('Access-Control-Allow-Origin', '*')
        response.send('hello')
    })
    
    // 处理 options 请求, 对于我们的例子来说, 不仅需要处理 origin, 还需要处理 headers
    app.options('*', (request, response) => {
        log('触发了预请求options')
        response.set('Access-Control-Allow-Origin', '*')
        response.header('Access-Control-Allow-Headers', 'Content-Type')
        response.end()
    })
    
    const main = () => {
        let server = app.listen(2300, () => {
            let host = server.address().address
            let port = server.address().port
    
            log(`应用实例,访问地址为 http://${host}:${port}`)
        })
    }
    
    if (require.main === module) {
        main()
    }
    

    html(crossOriginDemo.html):

    <!doctype html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>跨域demo</title>
        <style type="text/css">
            .ajaxButton {
                 100px;
                height: 50px;
                background: blue;
                color: #fff;
                display: flex;
                justify-content: center;
                align-items: center;
            }
        </style>
    </head>
    <body>
        <div class="ajaxButton">发送请求</div>
        <script>
            const log = console.log.bind(console)
    
            const ajax = (method, url, data, headers, callback) => {
                let r = new XMLHttpRequest()
                r.open(method, url, true)
    
                // 设置 headers
                Object.entries(headers).forEach(([k, v]) => {
                    r.setRequestHeader(k, v)
                })
                r.onreadystatechange = () => {
                    if (r.readyState === 4) {
                        callback(r.response)
                    }
                }
                if (method === 'POST') {
                    data = JSON.stringify(data)
                }
                r.send(data)
            }
            
            let ele = document.querySelector('.ajaxButton')
            ele.addEventListener('click', function () {
                // let url1 = 'http://localhost:2300/helloworld'
                let url2 = 'http://localhost:2300/singlecors'
                let method = 'GET'
                let data = {}
                let headers = {
                    'Content-Type': 'application/json',
                }
                ajax(method, url, data, headers, (r) => {
                    log('cors r is', r)
                })
            })
        </script>
    </body>
    </html>
    

    运行上面代码之后会发现, url1 依旧存在跨域问题, 不能正常访问数据; url2 不存在跨域问题, 能够正常访问数据, 这是因为对于请求来说, 不仅option 请求需要设置Access-Control-Allow-Headers 字段, GET 数据请求也要配置Access-Control-Allow-Headers 字段; 非简单请求是之前会有一个option 请求, 因此需要配置两次.

    5. demo 地址

    1. cors 解决方案
    2. 自定义HTTP 头部解决方案

    5. 参考链接

    1. 跨域资源共享 CORS 详解
  • 相关阅读:
    iptables单独记录一个日志文件
    centos7安装kvm
    查看一个启动的程序安装位置
    mysql-audit
    select 导出数据以|分割
    Codeforces 1105E 最大独立集 状态DP 中途相遇法
    Codeforces 1140E DP
    Codeforces 1152D DP
    GYM 101933E 状态压缩 + 记忆化搜索
    Codeforces 1151E 统计贡献
  • 原文地址:https://www.cnblogs.com/oulae/p/12784186.html
Copyright © 2020-2023  润新知