一、问题描述
最近接到一个需求,针对Nuxt2.x的一个项目进行SEO优化,需要对404页面的状态进行修改,将404页面的请求状态码改为301,而不是404:
二、解决方案
1.几种无效尝试
(1)layouts
下的error.vue
文件中使用asyncData
重设statusCode:
刚开始的思路是直接在layouts
下的error.vue
文件中进行设置:
// 设置状态码为301
async asyncData({ res }) {
res.statusCode = 301;
}
关于asyncData
API的介绍可以查看官网文档的介绍:
其中content
如下:
但实际上,上述的做法这是无效的。因为asyncData
在layouts
下的error.vue
中并不会执行,可以看一下官方文档的这段描述:
asyncData
. This hook can only be placed on page components. Unlike fetch, this hook does not display a loading placeholder during client-side rendering: instead, this hook blocks route navigation until it is resolved, displaying a page error if it fails.
(2)使用middleware
:
// middleware\setStatusCode.js
export default function (context) {
// 当访问的路由不存在时,context.res.statusCode此时也为200,也无法像下面那样使用context.error判断
// if (context.error && context.error.statusCode === 404) {
// context.res.statusCode = 301;
// }
const routeName = context.route.name;
const isPageExist = context.app.router.options.routes.some(route => route.name === routeName);
if (isPageExist) {
console.log(`The page ${routeName} exists`);
} else {
console.log(`The page ${routeName} does not exist`);
context.res.statusCode = 301;
}
}
// nuxt.config.js
router: {
...,
middleware: [ 'setStatusCode'],
...
}
这种方式如果对于正常存在的路由,是可以在middleware
中进行有效的修改,但是对于不存在的路由则无效,结果返回客户端的状态码依然是404。
2.可行方案
创建pages\error.vue
结合asyncData
:
<template>
<div class="page-404">
<div>
<img src="~/assets/images/error.png" alt="页面404">
</div>
</div>
</template>
<script>
export default {
// 设置状态码为301
async asyncData({ res }) {
res.statusCode = 301;
}
}
</script>
注:pages\error.vue
中的error
不要使用动态路由命名(即以下划线_
开头:_error
),因为它可能会与nuxt.config.js
中router.extendRoutes
里定义的动态路由冲突,而默认情况下pages\error.vue
会优先匹配(如果想知道为什么,可以查看项目根目录下.nuxt\router.js
,这个看看到nuxt最终生成的routes,在里面可以看到routes数组里path: "/:error"
会出现在router.extendRoutes
里定义的动态路由前面。当然如果非要使用_error
, 那么可以在尝试nuxt.config.js
中router.extendRoutes
里调整path: "/:error"
的顺序)。
现在访问一下/error
路径看看:
但上述这种方式只能针对一级访问路径/xxx
(比如,/error
)不存在的情况,如果访问的路径是多级(比如,/xxx/xxx
)的时候,客户端收到的响应码依然是404:
因此,我们需要针对无效访问的路径进行路由匹配定义:
// nuxt.config.js
router: {
extendRoutes (routes, resolve) {
routes.push(
...,
{
name: 'errorPage',
path: '*',
component: resolve(__dirname, 'pages/error.vue')
})
}
}
那么现在只要访问的链接不存在,nuxt返回给客户端的状态码就是301。