前端工程化(4):http-proxy-middleware在多環境下的代理應用

假設開發的時候存在如下幾套環境:javascript

  • 本身本地的MOCK環境(本身造一些爲所欲爲的數據)前端

  • RAP平臺環境(與後端約定好數據格式)vue

  • 後端開發人員的本地環境(與後端聯調)java

  • 阿里雲1測試環境(部署到測試環境,測試人員測試)webpack

  • 阿里雲2測試環境(環境緊張,須要部署到別的測試環境進行測試)ios

  • 阿里雲3測試環境(公司不差錢,買了至少5個服務器)git

  • 阿里雲4測試環境github

  • 阿里雲5測試環境web

    ......vue-cli

是的,就是有這麼多的環境等着你去訪問它們。那麼跑前端代碼的時候如何才能與各個環境進行聯調呢?最簡單直接的辦法就是修改proxy選項中的target,而後再從新執行開發腳本。這個方法在項目小的狀況你還能忍受,若是項目大的話,過長的編譯時間將直接消磨掉你的工做激情。

因此本文提出了一個能讓你在聯調時無縫切換不一樣環境的方案。若是你沒用到代理或者後端設置了跨域資源共享,這篇文章看看也無妨。若是你用到了http-proxy-middleware來處理跨域的問題,那這篇文章你更得看看。

第一步、配置環境

定義一個變量來承載所須要的路由鍵值對:

測試環境

let PROXY_ROUTER = {
  'dev-aliyun1.test.com': 'https://m-aliyun1.test.com:10454',
  'dev-aliyun2.test.com': 'https://m-aliyun2.test.com:10454',
  'dev-aliyun3.test.com': 'https://m-aliyun3.test.com:10454',
  'dev-aliyun4.test.com': 'https://m-aliyun4.test.com:10454',
  'dev-aliyun5.test.com': 'https://m-aliyun5.test.com:10454'
}
複製代碼

每一個開發域名dev-aliyunX.test.com域名都對應一個測試環境。

RAP環境

let PROXY_ROUTER = {
  ...
  'dev-rap.test.com': 'http://192.168.4.102:9999/mockjsdata/400',
}
複製代碼

用過RAP的同窗都知道,不一樣模塊掛着不一樣的id(就是👆url中的400),那這樣是否是得把所須要的id都寫上去?其實RAP提供了項目路由功能,能把不一樣模塊的id路由到一個模塊id上:

各個模塊之間使用逗號隔開,這樣只須要寫一個主id就行。

後端開發本地環境

// 填寫後端開發的ip地址和端口號
const devHostName = '172.16.9.xx'
const devServerPort = '8085'

let PROXY_ROUTER = {
  ...
  'dev-debug.test.com': `http://${devHostName}:${devServerPort}`
}
複製代碼

與後端開發聯調就避免不了要重啓項目了,由於後端開發的ip未知,須要手動填寫。

本地mock環境

src目錄下新建mock.js文件,寫入:

import Mock from 'mockjs' // 引入mock
import { mockMemberInfo } from './memberinfo'

Mock.mock('/api/rights/memberInfo', 'post', {
  {
    'code': '100',
    'result': {
        'level': 'trial',
        'name': '沈浩',
    },
    'resultDes': '',
    'success': true
  }
})
複製代碼

main.js中寫入:

if (process.env.NODE_ENV !== 'production' && window.location.hostname.indexOf('test') < 0) {
  require('./mock.js')
}
複製代碼

只有在開發環境而且是代理到本地mock的狀況下才啓用。無需在路由表中寫入對應的環境。

注:全部的開發域名都須要配置host,以下:127.0.0.1 dev-m-aliyun1.test.com ...

第二步、配置路由

統一前綴

統一對全部的接口進行代理處理,若是用了axios請求庫,能夠這麼配置:

axios.defaults.baseURL = process.env.NODE_ENV === 'production' ? '' : '/api'
複製代碼

路由分發

http-proxy-middleware提供了一個router選項(接收一個對象或者函數):可使用host或者path或者host+path匹配特定的請求來重寫option.target,也就是說router命中的url優先級高於target配置的url

處理前綴爲/api的接口:

let proxyTable = {
  '/api': ''
}

Object.entries(proxyTable).forEach(([key, value], index) => {
  proxyObj[key] = {
    target: value || 'http://localhost:8080',
    changeOrigin: true,
    pathRewrite (path, req) {
      return path.replace(/\/api/, '')
    },
    router (req) {
      let hostname = req.headers.host.split(':')[0]
      return value === '' ? PROXY_ROUTER[hostname] : value
    }
  }
})
複製代碼

經過接口請求的host,來匹配PROXY_ROUTER中對應的環境。若是匹配上了,router function返回匹配上的環境地址從而覆蓋掉target。若是沒匹配上,router function返回undefinedtarget生效,即代理本地mock環境。

在現實開發中還可能會出現一種奇葩的需求:你在a環境聯調,但有的接口還在b環境上。要解決這種問題,你只須要在proxyTable中加上:

let proxyTable = {
  '/api/cms/renderData': 'https://m-aliyun2.test.com:10454',
  '/api': ''
}
複製代碼

這樣不管你怎麼切換域名,/api/cms/renderData始終將會被代理到https://m-aliyun2.test.com:10454環境上。

順序很重要,第一個匹配上的將會生效。

總結

vue-cli3爲腳手架,在根目錄新建一個proxy.config.js文件:

let proxyObj = {}

// 與開發聯調的時候因爲未知 需手動填寫
const devHostName = '172.16.9.xx'
const devServerPort = '8085'
// 代理路由表
let PROXY_ROUTER = {
  'dev-m-aliyun1.test.com': 'https://m-aliyun1.test.com:10454', // 代理到阿里雲1測試環境
  'dev-m-aliyun2.test.com': 'https://m-aliyun2.test.com:10454', // 代理到阿里雲2測試環境
  'dev-m-aliyun3.test.com': 'https://m-aliyun3.test.com:10454', // 代理到阿里雲3測試環境
  'dev-m-aliyun4.test.com': 'https://m-aliyun4.test.com:10454', // 代理到阿里雲4測試環境
  'dev-m-aliyun5.test.com': 'https://m-aliyun5.test.com:10454', // 代理到阿里雲5測試環境
  'dev-rap.test.com': 'http://192.168.4.102:9999/mockjsdata/400', // 代理到rap環境
  'dev-debug.test.com': `http://${devHostName}:${devServerPort}` // 代理到後端開發人員的ip環境
}
// 代理接口
let proxyTable = {
  '/api/cms/renderData': 'https://m-aliyun2.test.com:10454',
  '/api': ''
}

Object.entries(proxyTable).forEach(([key, value], index) => {
  proxyObj[key] = {
    target: value || 'http://localhost:8080', // 代理到本地mock環境
    changeOrigin: true,
    pathRewrite (path, req) {
      return path.replace(/\/api/, '')
    },
    router (req) {
      let hostname = req.headers.host.split(':')[0]
      return value === '' ? PROXY_ROUTER[hostname] : value
    }
  }
})

module.exports = proxyObj
複製代碼

vue.config.js文件中修改:

const proxyBase = require('./proxy.config')

module.exports = {
  devServer: {
    proxy: proxyBase,
    disableHostCheck: true // 新版的webpack-dev-server出於安全考慮,默認檢查hostname,若是hostname不是配置內的,將中斷訪問
  },
  ...
}
複製代碼

上述代理配置之後,只須要經過切換域名就能夠無縫切換相應的測試環境,無需重啓前端服務,這對所處多個開發環境的前端開發者來講大大提升了工做效率。

其實,代理只是個輔助咱們開發的工具,將代理硬編碼到項目代碼中去的話,可維護性的確會差一點。但是,對於咱們軟件開發來講,工具只能成爲咱們的充分項,而不能成爲咱們的必要項。因此,個人這個方案各有利弊,你們能夠依照本身項目中的實際需求來酌情使用。

相關文章
相關標籤/搜索