http-proxy代理配置中遇到坑

8,040 阅读2分钟
  • 起因:使用vue-cli创建的vue项目,使用itunes开发接口获取付费app top榜单发现浏览器直接访问接口可以正常返回数据,vue.config.js中配置proxy接口一直返回404 not found

  • 解决过程:

    • 浏览器直接访问https://rss.itunes.apple.com/api/v1/us/ios-apps/top-paid/games/15/explicit.json可以返回数据
    • 使用node https请求也可以返回数据
    • 配置了一个http的ip接口可以正常返回数据,怀疑是该接口https的原因
    • 以为接口是https的原因,找了一个github的https接口配置代理可以获取到数据,排除https原因
    • 怀疑该链接有-这种特殊字,通过跟踪打印源码相应的数据并没有发现转发的请求地址并没有不同,排除该原因
    • 深度阅读源码vue.config.js-->webpack-->webpack-dev-server-->http-proxy-middleware-->http-proxy发现vue配置proxy代理最后实现是采用的http-proxy来实现代理转发,而经过一系列猜测实践排除以上原因后判断是该接口有一定的判别机制,通过打印请求的req.header后发现host字段是本地地址,猜测是否是因为host在目标接口服务中匹配不上造成的接口代理返回404错误,试图修改host,referer等属性不成功后,通过源码修改删除headers中的host属性接口可以正常返回数据如下:
    • // node_modules/http-proxy-middle/index.js文件
      function middleware(req, res, next) {
        // console.log('req--->\n', req)
        if (shouldProxy(config.context, req)) {
          var activeProxyOptions = prepareProxyRequest(req)
          console.log(req.headers.host)
          delete req.headers.host; //增加此行代码在真正的proxy前把host属性去掉
          proxy.web(req, res, activeProxyOptions)
        } else {
          next()
        }
      
        if (proxyOptions.ws === true) {
          // use initial request to access the server object to subscribe to http upgrade event
          catchUpgradeRequest(req.connection.server)
        }
      }
      
  • 番外 可见vue-cli创建的vue项目使用webpack打包,对webpack的定制配置需要在项目的根目录下创建vue.config.js来进行配置,代理跨域配置如下

    'use strict'
    module.exports = {
      // 配置 webpack-dev-server 行为。
      // 如果你的前端应用和后端 API 服务器没有运行在同一个主机上,你需要在开发环境下将 API 请求代理到 API 服务器。这个问题可以通过 vue.config.js 中的 devServer.proxy 选项来配置。
      devServer: {
        port: 9000,
        // 查阅 https://github.com/vuejs/vue-doc-zh-cn/vue-cli/cli-service.md#配置代理
        proxy: {
          // change xxx-api/login => mock/login
          // detail: https://cli.vuejs.org/config/#devserver-proxy
          '/api': {
            target: 'https://rss.itunes.apple.com',
            changeOrigin: true, // changes the origin of the host header to the target URL这个不知道怎么翻译更合适,默认为true否则会报400 no URL此类错误
            secure: false,      // 是否校验(或者说理会)对方https证书
            logLevel: 'debug',  // 日志等级,默认可以不配置用于调试时打印一些代理信息
            onProxyRes: function (proxyRes, req, res) { // 代理response事件
              console.log('res---->\n\n\n')
              // console.log(proxyRes.headers)
            },
            onProxyReq: function (proxyReq, req, res) { // 代理requset事件
              console.log('req---->\n\n\n')
              delete req.headers.host
            },
            // pathRewrite: {'^/api': ''}
          },
        }
      },
    }
    
  • 搬砖