zoukankan      html  css  js  c++  java
  • [web dev server proxy] 在实践中深入了解跨域 + devServer.proxy

    转载于: https://www.bianchengquan.com/article/144302.html

    1. 背景

    前段时间想在群里搞个钉钉机器人定时提醒自己写周报,然而又碰到了跨域的情况,代码大致如下:

    -- index.js --

    import axios from 'axios'
    function sxx () {
        axios.post('https://oapi.dingtalk.com/robot/send?XXXXXXXX', {
            msgtype: 'text',
            text: {
              content: '[sxx]: 我就是我, 是不一样的烟火'
            }
          })
    }
    sxx ()

    -- webpack.config.js --

    const path = require('path')
    module.exports = {
        entry: './index.js',
        devServer: {
            host: '0.0.0.0',
            port: 8080
        },
        plugins: [
          new HtmlWebpackPlugin()
        ],
        output: {
          filename: 'main.js',
          path: path.resolve(__dirname, './dist')
        }
    }

    报错如下所示:

    2. 回顾跨域的知识

    对于跨域,MDN里的这篇文章:HTTP访问控制(CORS)讲的很清晰。截取里面非常经典的图片(见下图),我们在domain-a.com网站下,访问domain-b.com的资源(png图片和eot的字体),这两个资源就会跨域,此时浏览器可能会阻止这两个资源请求的发送,也可能是跨站请求正常发送,但返回结果被浏览器拦截,具体要看浏览器的实现。

    那么,对应于我们本例中的跨域情况,我们是在0.0.0.0:8080下,访问oapi.dingtalk.com的资源,由于该请求跨域,浏览器直接阻止该请求的发送

    凭啥你说是阻止了请求的发送?
    通过charles可以看到post请求https://oapi.dingtalk.com/robot/send压根都没有发送,只是一个connect请求(况且若请求真的发送了,群里就会有钉钉机器人的消息了,返回的结果对我来说并没用)

    3. 更改origin是否可以处理跨域

    处理跨域常见的就是cors,服务器端设置Access-Control-Allow-Origin即可,可咱总不能让钉钉来添加吧?从跨域的原理看来,浏览器就是通过判断请求头中的origin结合请求的url来判断是否跨域的,那咱是不是可以更改origin来骗过浏览器?此时,咱们也有必要再了解下请求头中的host,origin字段:HTTP headers 之 host/referer/origin。于是,代码更改如下: -- index.js --

    import axios from 'axios'
    function sxx () {
        axios.post('https://oapi.dingtalk.com/robot/send?XXXXXXXX', {
            msgtype: 'text',
            text: {
              content: '[sxx]: 我就是我, 是不一样的烟火'
            }
          }, { headers: {'Origin': 'oapi.dingtalk.com'} })
    }
    sxx ()

    然而,直接报错了...主要看第一个报错:Refused to set unsafe header "Origin"

     

     搜索下stack overflow大佬们对于该报错的解释,其中的第一条留言就很到位,出于安全性的考虑,header中的origin是人家浏览器设置的,咱们无法更改它(想想也是,要是人人都可以更改origin,浏览器的同源策略岂不形同虚设)

      

    4. webpack的devServer.proxy处理了跨域

    之前看到慕课网里dell老师讲的devServer.proxy可以代理开发环境中的url,尝试了下竟然绕过了跨域,请求成功了,代码更改如下:
    -- index.js --

    import axios from 'axios'
    function sxx () {
        axios.post('/robot/send?XXXXXXXX', {
            msgtype: 'text',
            text: {
              content: '[sxx]: 我就是我, 是不一样的烟火'
            }
          })
    }
    sxx ()

    -- webpack.config.js --

    const path = require('path')
    module.exports = {
        entry: './index.js',
        devServer: {
            host: '0.0.0.0',
            port: 8080,
            proxy: {
                '/robot': {
                    target: 'https://oapi.dingtalk.com',
                    secure: false, // 协议是https的时候必须要写
                    changeOrigin: true
                }
            }
        },
        // ···省略了···太懒···
    }

    重点:添了changeOrigin: true后才可跨域,否则还是不行。那么重点就是理解为啥加上changeOrigin即可跨域

    5. changeOrigin如何解决跨域

    dell老师在视频里说changeOrigin字段是为了防止网站被爬数据,会验证请求的origin,若origin不是本网站的,则请求无法获得结果,看起来像是改变了header里的origin,但是刚不是尝试了咱们是无法更改origin的么?
    查看文档中关于changeOrigin字段的描述:

    changeOrigin: change the origin of the host header to the target url

    还是不太明白,然后查看源码(在http-proxy/common.js中):

     

     从源码里可以清晰的看到,设置了changeOrigin只是更改了request请求中的host,并不是origin,那么更加奇怪了,到底是如何绕过跨域的呢? 

    其实,devServer中的proxy就相当于charles进行url的代理,在sxx()执行后发送的请求是http://0.0.0.0:8080/robot/send?XXXXXXXX,我们是在0.0.0.0:8080下,当然不会限制这样的请求的发送,然后devServer的proxy通过配置将host更改为oapi.dingtalk.com,该请求就能正常进行,大致情况如下图所示:

     

    6. charles模拟

    为验证该想法,使用charles替换devServer.proxy进行url的代理,对于http://0.0.0.0:8080/robot/send?XXXXXXXX进行Breakpoint,更改该请求的host。 但是,又报错啦...如下图

     

     查询stack overflow中‘invalid Host header’,找到解决方法:只要在devServer中加个disableHostCheck: true即可。



  • 相关阅读:
    【006期】JavaSE面试题(六):泛型
    【005期】JavaSE面试题(五):String类
    【004期】JavaSE面试题(四):JavaSE语法(3)
    【003期】JavaSE面试题(三):JavaSE语法(1)
    【002期】JavaSE面试题(二):基本数据类型与访问修饰符
    【001期】 | JavaSE面试题(一):面向对象
    【000期】Java最全面试题库思维导图
    LeetCode 1. 两数之和(python3)实现
    虚拟网络学习笔记一:Linux虚拟网络
    快速排序(python实现)
  • 原文地址:https://www.cnblogs.com/0616--ataozhijia/p/15380262.html
Copyright © 2011-2022 走看看