This website requires JavaScript.

nuxt 过滤 query 参数

2018.09.27 11:07字数 3452阅读 306喜欢 1评论 0

今天发现了一个线上问题,我们的APP跳转内嵌H5时会默认query带一些参数,比如city之类的,但是有时运营人员配置页面链接地址时在不太了解的情况下,会手动加上city这些参数,恰巧你请求接口的时候需要这个参数,使用this.$route.query.city获取,form提交就会成为下图,会报400参数不规范,

这样重复query传参数显然是不规范的,这样使用this.$route.query.city获取回来是一个数组

解决该问题需要两点:

  1. 根源上配置的时候不要重复配置
  2. 前端对URLquery传参进行过滤

那么过滤参数怎样才能一劳永逸呢,避免每次取参数时判断是不是数组这中重复的代码。我们使用nuxt 这中服务端渲染的框架,开始想当然的想到在middleware中过滤,每次请求过来后执行middleware,过滤参数

先写个filterQuery的测试middleware 测试覆盖原来city,跑起来看看效果吧

控制台打印结果没啥问题

在页面里取一下试试,但结果不尽人意,this.$route.query.city 依然是数组多个值


看到这里,才发现自己太想当然了,nuxt是一套vue ssr的架构,服务端渲染的项目,每当一个新路由过来时,都会创建一个新的vue 实例,包括router, store这样是为了避免交叉请求状态的污染,页面中vue生命周期里this.$routevue实例上的;改动middlewareroute只在服务端比如asyncDatafetch时获取生效

测试一下
页面中asyncData获取一下参数

果然这里变了

那现在就是对routerquery做处理,其实vue-router为我们提供这样的函数 parseQuery/stringQuery(提供自定义查询字符串的解析/反解析函数。覆盖默认行为)

nuxt是对vue进行了封装,路由生成都是自动通过扫页面路径自动生成的,那我们去nuxt的源码里探个究竟,生成的核心是一个模板文件,lib/app/router.js文件,创建新router实例的工厂函数也在这个文件里

export function createRouter () {
  return new Router({
    mode: '<%= router.mode %>',
    base: '<%= router.base %>',
    linkActiveClass: '<%= router.linkActiveClass %>',
    linkExactActiveClass: '<%= router.linkExactActiveClass %>',
    scrollBehavior,
    routes: [
<%= _routes %>
    ],
    <% if (router.parseQuery) { %>parseQuery: <%= serialize(router.parseQuery).replace('parseQuery(', 'function(') %>,<% } %>
    <% if (router.stringifyQuery) { %>stringifyQuery: <%= serialize(router.stringifyQuery).replace('stringifyQuery(', 'function(') %>,<% } %>
    fallback: <%= router.fallback %>
  })
} 

在这里找到了需要的parseQuery 函数,这里的router.parseQuery是在 lib/common/options.js中配置的

router: {
    mode: 'history',
    base: '/',
    routes: [],
    middleware: [],
    linkActiveClass: 'nuxt-link-active',
    linkExactActiveClass: 'nuxt-link-exact-active',
    extendRoutes: null,
    scrollBehavior: null,
    parseQuery: false,
    stringifyQuery: false,
    fallback: false
  },

无论本地启动还是nuxt build的时候这个options.js都会与根目录下的nuxt.config.js配置项进行合并,所以也就一目了然了,加到nuxt.config.jsrouter下就好了,明确了就开干试试吧

nuxt.config.js加了如下代码

parseQuery: function (querystring) {
      let d = function (str) {
        try {
          return str && window.decodeURIComponent(str)
        } catch (e) {
          return str
        }
      }
      if (d(querystring).includes('?')) querystring = d(querystring).replace(/\?/g, '&')
      querystring = querystring.split('&')
      let params = {}
      let pair

      // march and parse
      for (let i = querystring.length - 1; i >= 0; i--) {
        pair = querystring[i].split('=')
        params[d(pair[0])] = d(pair[1])
      }
      return params
    }

不仅对重复的key过滤,也对url混入多个?做了合并过滤
结果就是 this.$router.query.city 进行了过滤,这里默认取第一个值

~本文完,有任何表述不清或者表达错误的,请大家指正~