解决webpack开发环境绝对路径接口跨域问题

1,968 阅读3分钟

在开发的时候,如果我们需要从子域名或者其他网站获得数据接口,可能会碰到跨域问题,这个时候常用的做法是修改hosts文件,或者配置一个反向代理服务器,难免有些麻烦,而且有时候需要测试的接口是开发环境的,就更加繁琐了。本来想用webpack-dev-server的反向代理来实现,发现他的实现方式是http-proxy-middleware中间件,只能反代path即相对路径

         foo://example.com:8042/over/there?name=ferret#nose
         \_/   \______________/\_________/ \_________/ \__/
          |           |            |            |        |
       scheme     authority       path        query   fragment

所以探索了一下,在尽量不干扰源码和生产环境的情况下,便捷的实现测试环境跨域接口的通用解决方案。
本文介绍两种方式,通过简单的修改配置文件和源码,实现用webpack-dev-server来实现接口的反向代理,同时不影响生产环境的打包结果。
两种方式都是一个原理:

  1. 通过plugin或者loader来替换所有其他域名接口的scheme+authority为一个不重复的相对路径前缀,本文是unique_dev_server
  2. webpack-dev-server反向代理这些相对路径。

第一种:通过definePlugin

这种方案需要修改源码,如果无法接受看第二种方案
先介绍第一步的配置。

// webpack.prod.js
    plugins: [
      ...,
      new webpack.DefinePlugin({
	      USER_SERVER: JSON.stringify('https://user.domain.com/')
    	})
    ]
// webpack.dev.js
    plugins: [
      ...,
      new webpack.DefinePlugin({
      //unique_dev_server随便写,只要是唯一且不冲突的
      	USER_SERVER: JSON.stringify('/unique_dev_server/')
	    })
    ]

这里开发环境要配置一个path前缀,要确保这个值是唯一的且和本域名的接口不冲突。
同时,配置好这个之后,要在对应的所有调用跨域名接口的js中修改url

/* global USER_SERVER */
fetch(USER_SERVER+"/api/test").then((res) => {
// fetch("https://user.doamin.com/api/test").then((res) => {

改成全局变量,如果你用了eslint,这里要加上global变量的注释。

  1. 第二步,针对/unique_dev_server这个url添加反向代理配置
devServer: {
    contentBase: path.join(__dirname, 'dist'),
    port: 9000,
    proxy: {
      '/unique_dev_server/': {
        target: 'http://localhost:8088/',
        pathRewrite: {'^/unique_dev_server/': ''},
        headers: {
          'referer': 'http://domain.com/'
        }
      }
    }
  },

重点是target要改成对应域名网址,还有pathRewrite要把前面的key去掉。
如果你的跨域名接口还对referer或者其他header有要求,还可以在这里添加。
完成这两步就大功告成了,如果你还有其他域名接口,只需要在defineplugin和proxy里增加对应的域名即可。

第二种通过string-replace-loader

还有一种不会对源代码产生影响的方式,就是通过string-replace-loader来实现第一步的替换
首先要安装这个loader

npm i string-replace-loader -D

然后修改开发环境webpack配置

// webpack.dev.js
    rules: [
      {
        test: /\.js$/,
        loader: 'string-replace-loader',
        options: {
          search: 'https://dev.example.com/',
          replace: '/unique_dev_server/'
        }
      }
    ]

proxy的配置看第一种方案的第二步。
这种方式的优点是不会对源代码产生修改,缺点是

  1. test文件过多,可能会影响编译速度
  2. 无法处理拼接url的情况(一般也不会有人拼接域名)
  3. 极低概率会误replace

如果你不想对源码产生影响,且可以接受以上缺点,建议你使用loader方案。