vuepress-reco / vuepress-theme-reco-1.x

🎨 This is the repo for vuepress-theme-reco 1.
http://v1.vuepress-reco.recoluan.com
MIT License
1.63k stars 320 forks source link

分类和标签包含中文会导致路由匹配不到,跳转至404页面 #276

Closed ATQQ closed 3 years ago

ATQQ commented 3 years ago

Bug report

What is actually happening?

在文章中,标签和分类如果包含中文,会在页面访问指定路由时404

---
title: api
date: 2020-05-29
categories: 
 - 中文分类
tags: 
 - 中文标签
---

复现步骤

  1. 脚手架创建项目,随意修改一个文章的分类/标签 包含中文

图片

  1. 运行后控制台会有警告

图片

提示路由的路径包含不可编码的字符

试验了一下 Vue-router是支持中文路由的

  1. 访问效果通过按钮目录点击导航没问题,但如果直接输入目标地址就是404

点它 ok 图片

直接访问它对应的路由,不ok

https://sugarat.top/categories/%E5%85%B6%E5%AE%83/

Other relevant information

ATQQ commented 3 years ago

问题的原因

浏览器对直接输入的中文url做了一次encode导致 匹配不到对应的path,然后就打到了404的路由

多年前有人在vue-router提过此问题 https://github.com/vuejs/vue-router/issues/838

在vue脚手架中使用中文路径是OK的不会触发warn,猜测是在哪执行了encode,待debug看执行路径

这个bug应该是在vuepress,在vuepress中出现中文路径的文件夹就会抛出上述的 warn

目前的解决方案

修改vue-router 的部分源码

node_modules/vue-router/dist/vue-router.esm.js

在match方法中加入以下语句,即可

function match (
    raw,
    currentRoute,
    redirectedFrom
  ) {

  if(typeof raw ==='string'){
     raw = decode(raw)
  }
  // ...code
}

图片

Mu-Yan commented 3 years ago

问题的原因

浏览器对直接输入的中文url准备一次编码导致匹配不到对应的路径,然后就打到了404的路由

多年前有人在vue-router提过此问题vuejs / vue-router#838

在vue脚手架中使用中文路径是OK的不会触发warn,猜测是在哪执行了编码,待调试看执行路径

这个bug应该是在vuepress,在vuepress中出现中文路径的文件夹就会抛出上述的warn

目前的解决方案

修改vue-router的部分源码

node_modules / vue-router / dist / vue-router.esm.js

在match方法中加入以下语句,即可

函数 匹配 (
    raw ,
    currentRoute ,
    redirectedFrom 
  ) { 

  if (typeof  raw  === 'string' ){ 
     raw  = 解码(raw )
  } 
  // ...代码
}

图片

直接修改vue-router源码无法治本,如果重新 npm install 就需要再次更改源码

可以通过 将主题更换至本地,而后修改 vuepress-theme-reco 本地主题的 enhanceApp.js 对应源码解决该问题,这样只要不更新主题就可一次解决

image

// enhanceApp.js
import postMixin from '@theme/mixins/posts'
import localMixin from '@theme/mixins/locales'
import { addLinkToHead } from '@theme/helpers/utils'
import { registerCodeThemeCss } from '@theme/helpers/other'

import Router from 'vue-router'

const router = new Router({
  mode: 'history'
})

// 防止相同路由跳转时报错
const VueRouterPush = Router.prototype.push
Router.prototype.push = function push (to) {
  return VueRouterPush.call(this, to).catch(err => err)
}

export default ({
  Vue,
  siteData,
  isServer,
  router
}) => {
  Vue.mixin(postMixin)
  Vue.mixin(localMixin)
  if (!isServer) {
    addLinkToHead('//at.alicdn.com/t/font_1030519_2ciwdtb4x65.css')
    registerCodeThemeCss(siteData.themeConfig.codeTheme)
  }

  router.beforeEach((to, from, next) => {
    // 解决非ASCII文件名的路由, 防止 404
    const decodedPath = decodeURIComponent(to.path)
    if (decodedPath !== to.path) {
      next(Object.assign({}, to, {
        fullPath: decodeURIComponent(to.fullPath),
        path: decodedPath
      }))
    } else {
      next()
    }
  })
}
ATQQ commented 3 years ago

问题的原因

浏览器对直接输入的中文url准备一次编码导致匹配不到对应的路径,然后就打到了404的路由 多年前有人在vue-router提过此问题vuejs / vue-router#838 在vue脚手架中使用中文路径是OK的不会触发warn,猜测是在哪执行了编码,待调试看执行路径 这个bug应该是在vuepress,在vuepress中出现中文路径的文件夹就会抛出上述的warn

目前的解决方案

修改vue-router的部分源码 node_modules / vue-router / dist / vue-router.esm.js 在match方法中加入以下语句,即可

函数 匹配 (
    raw ,
    currentRoute ,
    redirectedFrom 
  ) { 

  if (typeof  raw  === 'string' ){ 
     raw  = 解码(raw )
  } 
  // ...代码
}

图片

直接修改vue-router源码无法治本,如果重新 npm install 就需要再次更改源码

可以通过 将主题更换至本地,而后修改 vuepress-theme-reco 本地主题的 enhanceApp.js 对应源码解决该问题,这样只要不更新主题就可一次解决

image

// enhanceApp.js
import postMixin from '@theme/mixins/posts'
import localMixin from '@theme/mixins/locales'
import { addLinkToHead } from '@theme/helpers/utils'
import { registerCodeThemeCss } from '@theme/helpers/other'

import Router from 'vue-router'

const router = new Router({
  mode: 'history'
})

// 防止相同路由跳转时报错
const VueRouterPush = Router.prototype.push
Router.prototype.push = function push (to) {
  return VueRouterPush.call(this, to).catch(err => err)
}

export default ({
  Vue,
  siteData,
  isServer,
  router
}) => {
  Vue.mixin(postMixin)
  Vue.mixin(localMixin)
  if (!isServer) {
    addLinkToHead('//at.alicdn.com/t/font_1030519_2ciwdtb4x65.css')
    registerCodeThemeCss(siteData.themeConfig.codeTheme)
  }

  router.beforeEach((to, from, next) => {
    // 解决非ASCII文件名的路由, 防止 404
    const decodedPath = decodeURIComponent(to.path)
    if (decodedPath !== to.path) {
      next(Object.assign({}, to, {
        fullPath: decodeURIComponent(to.fullPath),
        path: decodedPath
      }))
    } else {
      next()
    }
  })
}

多谢嘞👍

ATQQ commented 3 years ago

问题的原因

浏览器对直接输入的中文url准备一次编码导致匹配不到对应的路径,然后就打到了404的路由 多年前有人在vue-router提过此问题vuejs / vue-router#838 在vue脚手架中使用中文路径是OK的不会触发warn,猜测是在哪执行了编码,待调试看执行路径 这个bug应该是在vuepress,在vuepress中出现中文路径的文件夹就会抛出上述的warn

目前的解决方案

修改vue-router的部分源码 node_modules / vue-router / dist / vue-router.esm.js 在match方法中加入以下语句,即可

函数 匹配 (
    raw ,
    currentRoute ,
    redirectedFrom 
  ) { 

  if (typeof  raw  === 'string' ){ 
     raw  = 解码(raw )
  } 
  // ...代码
}

图片

直接修改vue-router源码无法治本,如果重新 npm install 就需要再次更改源码 可以通过 将主题更换至本地,而后修改 vuepress-theme-reco 本地主题的 enhanceApp.js 对应源码解决该问题,这样只要不更新主题就可一次解决 image

// enhanceApp.js
import postMixin from '@theme/mixins/posts'
import localMixin from '@theme/mixins/locales'
import { addLinkToHead } from '@theme/helpers/utils'
import { registerCodeThemeCss } from '@theme/helpers/other'

import Router from 'vue-router'

const router = new Router({
  mode: 'history'
})

// 防止相同路由跳转时报错
const VueRouterPush = Router.prototype.push
Router.prototype.push = function push (to) {
  return VueRouterPush.call(this, to).catch(err => err)
}

export default ({
  Vue,
  siteData,
  isServer,
  router
}) => {
  Vue.mixin(postMixin)
  Vue.mixin(localMixin)
  if (!isServer) {
    addLinkToHead('//at.alicdn.com/t/font_1030519_2ciwdtb4x65.css')
    registerCodeThemeCss(siteData.themeConfig.codeTheme)
  }

  router.beforeEach((to, from, next) => {
    // 解决非ASCII文件名的路由, 防止 404
    const decodedPath = decodeURIComponent(to.path)
    if (decodedPath !== to.path) {
      next(Object.assign({}, to, {
        fullPath: decodeURIComponent(to.fullPath),
        path: decodedPath
      }))
    } else {
      next()
    }
  })
}

多谢嘞👍

问题的原因

浏览器对直接输入的中文url准备一次编码导致匹配不到对应的路径,然后就打到了404的路由 多年前有人在vue-router提过此问题vuejs / vue-router#838 在vue脚手架中使用中文路径是OK的不会触发warn,猜测是在哪执行了编码,待调试看执行路径 这个bug应该是在vuepress,在vuepress中出现中文路径的文件夹就会抛出上述的warn

目前的解决方案

修改vue-router的部分源码 node_modules / vue-router / dist / vue-router.esm.js 在match方法中加入以下语句,即可

函数 匹配 (
    raw ,
    currentRoute ,
    redirectedFrom 
  ) { 

  if (typeof  raw  === 'string' ){ 
     raw  = 解码(raw )
  } 
  // ...代码
}

图片

直接修改vue-router源码无法治本,如果重新 npm install 就需要再次更改源码

可以通过 将主题更换至本地,而后修改 vuepress-theme-reco 本地主题的 enhanceApp.js 对应源码解决该问题,这样只要不更新主题就可一次解决

image

// enhanceApp.js
import postMixin from '@theme/mixins/posts'
import localMixin from '@theme/mixins/locales'
import { addLinkToHead } from '@theme/helpers/utils'
import { registerCodeThemeCss } from '@theme/helpers/other'

import Router from 'vue-router'

const router = new Router({
  mode: 'history'
})

// 防止相同路由跳转时报错
const VueRouterPush = Router.prototype.push
Router.prototype.push = function push (to) {
  return VueRouterPush.call(this, to).catch(err => err)
}

export default ({
  Vue,
  siteData,
  isServer,
  router
}) => {
  Vue.mixin(postMixin)
  Vue.mixin(localMixin)
  if (!isServer) {
    addLinkToHead('//at.alicdn.com/t/font_1030519_2ciwdtb4x65.css')
    registerCodeThemeCss(siteData.themeConfig.codeTheme)
  }

  router.beforeEach((to, from, next) => {
    // 解决非ASCII文件名的路由, 防止 404
    const decodedPath = decodeURIComponent(to.path)
    if (decodedPath !== to.path) {
      next(Object.assign({}, to, {
        fullPath: decodeURIComponent(to.fullPath),
        path: decodedPath
      }))
    } else {
      next()
    }
  })
}

这个直接安排个PR给主题吧哈哈

Mu-Yan commented 3 years ago

这只是我目前使用一种解决方法,毕竟遇到了这个问题。 我看案例展示的基本没这个问题,不知道是不是都自定义了一波,还是配置不一致原因。

Mu-Yan commented 3 years ago

@recoluan 有空的话,麻烦看下这个问题是否是个例问题

ATQQ commented 3 years ago

我猜应该不是个例问题,我拿reco主题(1.5.7)的cli创建的模板项目,在不同操作系统都有这个问题

主要就是路由中匹配不到 encode后的path

vuepress貌似本身也存在这个问题,即vuepress也没有单独处理Unicode的字符路径,感觉中文(Unicode字符)相关的问题有一堆

Mu-Yan commented 3 years ago

嗯,我遇到问题主要是分类名是中文或者空格等,我的版本也是 1.5.7, 我也试了案例里常见的 1.5.5 版本 都存在这个问题,而后才进行的修改源码

hellorayza commented 3 years ago

我也发现了这个问题。 categories使用中文,从categories进入md页面后点击返回进入404. 环境:

    "vuepress": "^1.7.1",
    "vuepress-theme-reco": "^1.5.7"

btw: hexo的categories解析规则是:

- FE
- -
- vue

成同级目录

- FE
- vue

则vue为FE的二级目录。

vuepress中,似乎只能分一级目录,用法如下:

- FE
- vue

或者是

- FE
-
- vue

能说下原因吗?或者如何快速迁移

ATQQ commented 3 years ago

这个中文404的问题的原因是:浏览器对直接输入的中文url准备一次编码导致匹配不到对应的路径,然后就打到了404的路由

我理解这个目录解析是很灵活的,与目录深度没关系吧

快速迁移的话 可以自己用Node写一个自动化脚本即可

recoluan commented 3 years ago

@ATQQ @Mu-Yan

你们是不是都是在自己的服务器上配置的 Nginx,我的都是托管在第三方平台上,所以没出现你们的问题。

原来群里讨论过这个问题,好像是让 Nginx 支持中文路径即可,我个人没做过尝试,欢迎继续讨论。

ATQQ commented 3 years ago

嗯,自己的服务器,部署在Nginx上,Nginx应该是支持中文的 没问题 ,如果不支持的话,就找不到对应的资源 返回的页面应该是 下面这种样子

图片

目前因为浏览器对中文资源的url进行了如下的encode,js拿到的path是没进行decode的path,所以匹配不到,就打到了配置的404路由页面

图片

解决方案应该就是 上面说的两种:

  1. 在build的时候router加入 encode后的path
  2. 客户端(浏览器)在执行router match 方法的前,先进行一下decode

只是现在需要一个方案(可以是plugin的形式),在不修改 主题/vue-router源码的情况下解决此问题

Mu-Yan commented 3 years ago

我部署在 GitHub Pages 的

ZhangXL-WaHaHa commented 3 years ago

可以使用原型链修改match函数,https://blog.csdn.net/weixin_44113868/article/details/118052046