欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Vue 项目代理设置的优化

程序员文章站 2024-01-18 21:49:16
vue 类的项目开发中项目结构基本都是类似于 vue-cli 生成的方式,这种方式开发中,最常用到的模式是开启代理进行 mock 调试或远程调试,也就是使用了 vue-cl...

vue 类的项目开发中项目结构基本都是类似于 vue-cli 生成的方式,这种方式开发中,最常用到的模式是开启代理进行 mock 调试或远程调试,也就是使用了 vue-cli 设置的配置 proxytable 或者直接使用 webpack-dev-server提供的 proxy 选项。它是采用了 http-proxy 库,所以具体配置可查看:

利用配置的这些参数我们可以做更为灵活的配置,达到更好的效果

使用需求

假设我们本地开发目前以下几种状态:

  • 本地开发,数据使用本地的 mock server
  • 涉及权限接口使用本地 mock 数据,其他全部使用指定的一台远程机器
  • 涉及权限接口使用本地 mock 数据,其他数据分接口使用不同的远程机器
  • 所有接口使用同一台远程机器

方案

先看下经典的proxytable 写法:

proxytable: {
 '/authui/': {
  target: target,
  changeorigin: true
 },
 '/vendor/': {
  target: target,
  changeorigin: true
 }
}

其中用到了 changeorigin 字段,主要是用于改变请求的 header。细化下需求:

  • 本地开发:target 指向 localhost 的某个端口即可。至于 host 的验证肯定是不需要的
  • 部分本地,其他固定的一台远程机器:需要配置 localhost 和远程的地址,远程地址多半是需要验证 host 的
  • 同二,但机器有多台:需要手动配置多台机器
  • 同一台远程机器,此时机器可能要严格验证,即 ip 也必须使用域名,配置好系统 host 才可使用

说明:严格验证 host 和普通验证 host 区别主要在于严格验证时,请求的 url 必须是远程机器的域名,
不能直接修改请求的 header 的 host 实现,即必须在系统 host 层面配置好域名。

分析完成具体需求好,就开始准备实现的方式。原有开发方式是执行 npm run dev,如果我们需要在命令行层面添加配置,就需要设置为 npm run dev --param=paramvalue 的方式。对于使用 npm 的 script 脚本执行的命令,
它参数的获取无法通过 process.env 获得,而且通过 process.env.npm_config_paramname 的方式获取,
使用现成的命令行参数解析库也不是很方便,但为了省事,暂时还是使用 npm 自带的解析。

请求发起过程中需要以下几个参数:

  • host: 发起请求需要指向的 host,可能每台机器验证并不相同
  • port: 代理转发的端口
  • receiver: 用于 push 的远程地址,内包含了 ip 地址,为了省事,没有单独列出 ip 地址

然后定义代理请求自定义类型,用于配置:

  • local: 本地地址,即 localhost
  • remote: 指定的远程机器
  • 其他自定义类型:用于在配置文件中已经指定的其他类型
  • 原版本的请求,如 'http://xxx' 或者 object 类型的配置,此类代理永不处理

根据需要,我们添加以下几个参数用于控制代理指向地址:

  1. rd: 远程机器的地址
  2. focus: 严格模式,所有自定义类型的代理转换为指定的 rd 机器,只在存在 rd 参数时可用
  3. alllocal:自定义类型代理全部指向本地
  4. host:请求发现是否使用 host,而不是 ip 地址

总结一下(序号指向前面的需求):

  • 需要使用 host 进行访问的情形:4
  • 需要更改 host:除 localhost 外都需要更改
  • 需要对已有类型进行转换:1: 需要将所有自定义类型都转换为 local, 2和3:什么也不转换,4:所有的自定义类型全部转换为

remote 类型

这么一看,貌似 host 是不需要的,它的存在主要是针对某些 机器可能需要使用 host 的方式,所以还是保留一下。

实现

逻辑理清了就很简单了,配置文件设置为:

module.export = {
 rd1: {
  host: 'dev1.example.com',
  port: 8838,
  receiver: 'http://1.1.1.1:8888/receiver'
 },
 rd2: {
  host: 'dev2.example.com',
  port: 8838,
  receiver: 'http://1.1.1.1:8888/receiver'
 }
}

proxytable 配置方式

{
 proxytable: {
  '/api1': 'remote',
  '/api2': 'rd2',
  '/auth/xx': 'local',
  '/other': 'http://example.com'
 }
}

获取 proxytable 的代码:

// 处理 proxytable
const releaseconfig = require('../config/release.conf.js')
const rdconfig = releaseconfig[process.env.npm_config_rd]
const isallremote = process.env.npm_config_focus
const usehost = isallremote || process.env.npm_config_host
// 是否本机开发,本机开发 remote 会指向 local
const isalllocal = process.env.npm_config_alllocal
module.exports = function (proxy) {
 const localurl = `http://localhost:${proxy.localproxyport}`
 const defaulthost = proxy.defaultrdhost || 'dev-example.com'
 const localproxyport = proxy.localproxyport || 8787
 const finalconfig = formatreleaseconfig(releaseconfig)
 const remote = finalconfig.remote || {}
 if (process.env.npm_config_rd) {
  if (!rdconfig) {
   throw new typeerror('rd 机器名称不存在,请在 config/release.conf.js 中进行配置')
  }
  if (!remote.ip) {
   throw new error('请配置 rd 机器的 receiver')
  }
 }
 if (isallremote && !rdconfig) {
  throw new typeerror('focus 只能在提供了 rd 名称后可设置')
 }
 function formatreleaseconfig (config) {
  const result = {}
  object.keys(config).map((key) => {
   const value = config[key]
   const ipmatch = (value.receiver || '').match(/:\/\/(.*?):\d/)
   const ip = ipmatch && ipmatch[1]
   result[key] = {
    ip,
    host: value.host || defaulthost,
    port: value.port || '8391'
   }
  })
  // 设置 remote
  if (rdconfig) {
   const ipmatch = (rdconfig.receiver || '').match(/:\/\/(.*?):\d/)
   const ip = ipmatch && ipmatch[1]
   result.remote = {
    ip,
    host: rdconfig.host || defaulthost,
    port: rdconfig.port || '8391'
   }
  }
  // 设置 local
  result.local = {
   ip: 'localhost',
   host: 'localhost',
   port: localproxyport
  }
  return result
 }
 function setproxy (proxytable) {
  const result = {}
  object.keys(proxytable).foreach((api) => {
   let type = proxytable[api]
   const iscustomtype = typeof type === 'string' && !/^http/.test(type)
   if (iscustomtype && type !== 'remote' && type !== 'local' && !finalconfig[type]) {
    throw new typeerror(`代理类型${type}不正确,请提供 http 或 https 类型的接口,或者指定正确的 release 机器名称`)
   }
   if (type === 'remote' && !finalconfig.remote) {
    type = 'local'
   }
   if (iscustomtype) {
    if (isallremote && type !== 'remote') {
     type = 'remote'
    }
    if (isalllocal && type !== 'local') {
     type = 'local'
    }
   }
   const targetconfig = finalconfig[type]
   let target = type
   if (targetconfig) {
    target = {
     target: `http://${usehost ? targetconfig.host : targetconfig.ip}:${targetconfig.port}`,
     // 使用 host 时需要转换,其他不需要转换
     headers: {
      host: `${targetconfig.host}:${targetconfig.port}`
     }
    }
   }
   result[api] = target
  })
  return result
 }
 return {
  proxytable: setproxy(proxy.proxytable),
  host: remote.host || defaulthost
 }
}

用法

用法中需要配置两种指向:系统 host 和浏览器代理 host。
之所以要两种 host, 本质上是因为接口使用的域名
和我们的本地访问的域名是相同的,同一域名无法指向两个地址,所以相当于对浏览器端进行了拦截。
系统 host 推荐使用 switchhost 进行切换,浏览器推荐使用 whistle 进行切换。

本地开发

host 配置:无
whistle 配置:默认的域名

127.0.0.1 dev.example.com

启动命令:

npm run dev
npm run dev --alllocal

注: 此时 proxytable 中配置的 remote 全部转换为 local,在 alllocal 参数时将所有自定义类型转换为 local

本地 + 1 台远程

host 配置:无
whistle 配置:默认的域名
127.0.0.1 dev1.example.com
127.0.0.1 dev2.example.com

启动命令:

npm run dev --rd=rd1
npm run dev --rd=rd1 --host

注: --host 表示使用访问使用 host 而非 ip,使用时需要 host 地址

本地 + n 台远程

host 配置:无

whistle 配置:默认的域名

127.0.0.1 dev1.example.com

127.0.0.1 dev2.example.com

{
 proxytable: {
  '/api1': 'rd1',
  '/api2': 'rd2',
  '/auth/xx': 'local',
  '/other': 'http://example.com'
 }
}

proxytable 配置:

启动命令:

npm run dev

远程 1 台机器

host 配置:

1.1.1.1 dev1.example.com
1.1.1.1 dev2.example.com

whistle 配置:默认的域名

127.0.0.1 dev1.example.com
127.0.0.1 dev2.example.com

启动命令:

npm run dev --rd=rd1 --focus

组件优化

vue 的组件化深受大家喜爱,到底组件拆到什么程度算是合理,还要因项目大小而异,小型项目可以简单几个组件搞定,甚至不用 vuex,axios 等等,如果规模较大就要细分组件,越细越好,包括布局的封装,按钮,表单,提示框,轮播等,推荐看下 element 组件库的代码,没时间写这么详细可以直接用 element 库,分几点进行优化

•组件有明确含义,只处理类似的业务。复用性越高越好,配置性越强越好。

•自己封装组件还是遵循配置 props 细化的规则。

•组件分类,我习惯性的按照三类划分,page、page-item 和 layout,page 是路由控制的部分,page-item 属于 page 里各个布局块如 banner、side 等等,layout 里放置多个页面至少出现两次的组件,如 icon, scrolltop 等

总结

细挖需求,可能还有更简单的方式,在大部分情况下能够减少代码修改,是 webpack 配置型的实现吧。当然,方式并不完美,尤其在 mac 下,居然不能支持 --rd xx 这种形式,可以有类似的库吧,后续可以做为深入的内容。

以上所述是小编给大家介绍的vue 项目代理设置的优化,希望对大家有所帮助