跳至内容

不同的历史模式

创建路由实例时的 history 选项允许我们在不同的历史模式之间选择。

哈希模式

哈希历史模式使用 createWebHashHistory() 创建

js
import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    //...
  ],
})

它在实际 URL 之前使用一个哈希字符 (#) 来内部传递。由于 URL 的这一部分永远不会发送到服务器,因此它不需要服务器级别的任何特殊处理。但是,它对 SEO 影响很大。如果这是你的顾虑,请使用 HTML5 历史模式。

HTML5 模式

HTML5 模式使用 createWebHistory() 创建,是推荐的模式

js
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    //...
  ],
})

使用 createWebHistory() 时,URL 将看起来“正常”,例如 https://example.com/user/id。漂亮!

但是,这里有一个问题:由于我们的应用程序是一个单页面的客户端应用程序,如果没有适当的服务器配置,用户如果直接在浏览器中访问 https://example.com/user/id,就会收到 404 错误。现在这很丑。

不用担心:要解决这个问题,你只需要在服务器上添加一个简单的通配符回退路由。如果 URL 与任何静态资产不匹配,它应该提供你的应用程序所在的同一个 index.html 页面。再次漂亮!

内存模式

内存历史模式不假设浏览器环境,因此不与 URL 交互也不自动触发初始导航。这使其非常适合 Node 环境和 SSR。它使用 createMemoryHistory() 创建,需要你在调用 app.use(router) 后推送初始导航

js
import { createRouter, createMemoryHistory } from 'vue-router'

const router = createRouter({
  history: createMemoryHistory(),
  routes: [
    //...
  ],
})

虽然不推荐,但你可以在浏览器应用程序中使用此模式,但请注意将没有历史记录,这意味着你将无法后退前进

示例服务器配置

注意:以下示例假设你从根文件夹提供你的应用程序。如果你部署到子文件夹,你应该使用 Vue CLI 的 publicPath 选项 和相关的 路由的 base 属性。你还需要调整以下示例以使用子文件夹而不是根文件夹(例如,将 RewriteBase / 替换为 RewriteBase /name-of-your-subfolder/)。

Apache

<IfModule mod_negotiation.c>
  Options -MultiViews
</IfModule>

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>

除了 mod_rewrite,你还可以使用 FallbackResource

nginx

nginx
location / {
  try_files $uri $uri/ /index.html;
}

原生 Node.js

js
const http = require('http')
const fs = require('fs')
const httpPort = 80

http
  .createServer((req, res) => {
    fs.readFile('index.html', 'utf-8', (err, content) => {
      if (err) {
        console.log('We cannot open "index.html" file.')
      }

      res.writeHead(200, {
        'Content-Type': 'text/html; charset=utf-8',
      })

      res.end(content)
    })
  })
  .listen(httpPort, () => {
    console.log('Server listening on: https://127.0.0.1:%s', httpPort)
  })

Express 与 Node.js

对于 Node.js/Express,请考虑使用 connect-history-api-fallback 中间件

Internet Information Services (IIS)

  1. 安装 IIS UrlRewrite
  2. 在你的站点根目录中创建一个 web.config 文件,内容如下
xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="Handle History Mode and custom 404/500" stopProcessing="true">
          <match url="(.*)" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
          </conditions>
          <action type="Rewrite" url="/" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

Caddy v2

try_files {path} /

Caddy v1

rewrite {
    regexp .*
    to {path} /
}

Firebase 托管

将此添加到你的 firebase.json

json
{
  "hosting": {
    "public": "dist",
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}

Netlify

创建一个 _redirects 文件,该文件包含在你的部署文件中

/* /index.html 200

在 vue-cli、nuxt 和 vite 项目中,此文件通常位于名为 staticpublic 的文件夹下。

你可以在 Netlify 文档 中了解更多关于语法的知识。你也可以 创建一个 netlify.toml 来将重定向与其他 Netlify 功能结合起来。

Vercel

在你的项目的根目录下创建一个 vercel.json 文件,内容如下

json
{
  "rewrites": [{ "source": "/:path*", "destination": "/index.html" }]
}

警告

这里有一个警告:你的服务器将不再报告 404 错误,因为所有未找到的路径现在都提供你的 index.html 文件。要解决这个问题,你应该在你的 Vue 应用程序中实现一个通配符路由来显示一个 404 页面

js
const router = createRouter({
  history: createWebHistory(),
  routes: [{ path: '/:pathMatch(.*)', component: NotFoundComponent }],
})

或者,如果你使用的是 Node.js 服务器,你可以使用服务器端的路由来实现回退,以匹配传入的 URL,如果路由不匹配,则返回 404。查看 Vue 服务器端渲染文档 以了解更多信息。