10. 示例 [nuxt-07]:客户端与服务器上下文
10.1. Présentation
示例 [nuxt-07] 旨在从服务器端和客户端两个角度探讨对象 [context]。请注意,[nuxt] 应用程序中的这两个参与者是分离的:它们除了以下内容外没有任何共享:
- 服务器愿意发送给客户端的内容(包含在 HTTP 响应及发送的页面中);
- 客户端愿意发送给服务器的内容(包含在其 HTTP 请求中);
因此,正如我们将看到的,尽管服务器和客户端操作的对象名称相同,但它们并非同一事物:它们有时可能是彼此的副本,但绝不会拥有相同的引用。修改客户端对象对服务器端同名对象没有任何影响,反之亦然。
示例 [nuxt-07] 最初是通过复制示例 [nuxt-01] 获得的:

- 在 [2] 中,我们将添加一个客户端和服务器共用的插件;
- 在 [3] 中,我们将对页面 [index] 进行一些修改;
10.2. 插件 [common / main.js]
插件 [common / main.js] 由客户端和服务器同时执行:这是由于以下 [nuxt.config.js] 配置所致:
/*
** Plugins to load before mounting the App
*/
plugins: [{ src: '~/plugins/common/main.js' }],
- 第 4 行:由于缺少 [mode] 属性,导致插件 [~/plugins/common/main.js] 将同时由客户端和服务器执行:先由服务器执行,然后由客户端执行;
该插件如下:
/* eslint-disable no-undef */
/* eslint-disable no-console */
export default function(...args) {
// 谁在执行这段代码?
console.log('[main server], process.server=', process.server, 'process.client=', process.client)
const who = process.server ? 'server' : 'client'
const main = '[main ' + who + ']'
// 参数个数
console.log(main + ', il y a', args.length, 'arguments')
// 第一个参数
const context = args[0]
// 上下文键
dumpkeys(main + ', context', context)
// 应用程序
dumpkeys(main + ', context.app', context.app)
// 路由
dumpkeys(main + ', context.route', context.route)
console.log(main + ', context.route=', context.route)
// 路由器
dumpkeys(main + ', context.app.router', context.app.router)
// router.options.routes
dumpkeys(main + ', context.app.router.options.routes', context.app.router.options.routes)
console.log(main + ', context.app.router.options.routes=', context.app.router.options.routes)
// 第二个参数
const inject = args[1]
console.log('inject=', typeof inject)
}
function dumpkeys(message, object) {
// [object] 的密钥列表
const ligne = 'Liste des clés [' + message + ']'
console.log(ligne)
// 密钥列表
if (object) {
console.log(Object.keys(object))
}
}
- 第31-39行:函数[dumpkeys]列出了作为第二个参数传递的对象的属性。该列表前缀为作为第一个参数传递的消息;
- 第3行:我们需要知道该函数接收多少个参数。为此,我们使用[...args]语法,这将把函数的实际参数放入数组[args]中。我们将发现共有两个参数;
- 第 5 行:显示代码的执行方,是服务器还是客户端;
- 第 6 行:代码的执行者,客户端或服务器;
- 第7行:日志中使用的字符串常量;
- 第 12 行:我们将发现插件接收的第一个参数是执行者的上下文;
- 第14行:对象[context]的键列表;
- 第16行:我们将发现对象[context]有一个属性[app],该属性代表应用程序[nuxt];
- 第 18 行:我们将发现对象 [context] 具有一个属性 [route],该属性表示路由器的当前路由;
- 第 21 行:我们将发现对象 [app] 有一个属性 [router],该属性代表路由器;
- 第 23 行:对象 [router.options.routes] 表示应用程序的各个路由;
- 第 27-28 行:插件的第二个参数是我们在示例 [nuxt-06] 中使用的函数 [inject];
10.3. 由服务器执行的插件
运行时,服务器显示如下内容:
- 第 11-12 行:我们之前已经使用过 [base] 和 [env] 属性,其值来自文件 [nuxt.config.js];
- 第 8 行:属性 [app] 指代应用程序 [nuxt];
- 第 18 行:属性 [route] 表示路由器的当前路由,即服务器将发送的页面;
- 第 13 行:客户端浏览器的请求 HTTP;
- 第 14 行:服务器的响应 HTTP;
[context.app]的属性列表如下:
- 第3行:属性[router]使我们能够访问该应用程序的路由器。 这在 [nuxt] 中非常重要,因为路由器是由 [nuxt] 自身定义的,而非由开发人员定义。该属性为开发人员提供了修改路由器的权限;
[context.route]的属性列表如下:
服务器启动时的 [context.route] 路由如下:
- 第 2 行:可以看到服务器的下一页是 [index],其路径为 [/](第 10 行);
- 第22行:属性[meta]用于为路由添加属性;
服务器路由器 [context.app.router] 的属性如下:
应用程序的各个路由位于 [context.app.router.options.routes] 属性中:
最后是第二个参数:
10.4. 服务器上的页面 [index]
页面 [index] 如下所示:
<!-- 主页 -->
<template>
<Layout :left="true" :right="true">
<!-- 导航 -->
<Navigation slot="left" />
<!-- 消息-->
<b-alert slot="right" show variant="warning">
Home
</b-alert>
</Layout>
</template>
<script>
/* eslint-disable no-undef */
/* eslint-disable no-console */
/* eslint-disable nuxt/no-env-in-hooks */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Home',
// 使用的组件
components: {
Layout,
Navigation
},
data() {
return {
who: process.server ? 'server' : 'client'
}
},
// 生命周期
beforeCreate() {
// 客户端与服务器
console.log('[home beforeCreate]')
},
created() {
// 客户端与服务器
console.log('[home ' + this.who + ' created]')
this.dumpkeys('[home ' + this.who + ' created], this.$nuxt', this.$nuxt)
this.dumpkeys('[home ' + this.who + ' created], this.$nuxt.context', this.$nuxt.context)
},
beforeMount() {
// 仅客户端
console.log('[home ' + this.who + ' beforeMount]')
},
mounted() {
// 仅客户端
console.log('[home ' + this.who + ' mounted]')
},
methods: {
dumpkeys(message, object) {
// [object] 的密钥列表
const ligne = 'Liste des clés [' + message + ']'
console.log(ligne)
if (object) {
console.log(Object.keys(object))
}
}
}
}
</script>
- 第 43 行:我们已经看到,页面的上下文可以在 [this.$nuxt.context] 中找到;
- 第 42 行:同时显示了对象 [this.$nuxt] 的属性;
该页面由服务器执行后,会生成以下日志:
页面 [index] 中的服务器上下文属性如下:
这些属性与插件中的 [context] 对象中的属性相同。
10.5. 由客户端执行的插件
一旦服务器将页面 [index] 发送至客户端浏览器,客户端脚本便开始运行。此时将执行插件 [main.js]。相关日志如下:
其中包含与服务器端类似的属性,但部分属性已消失,另有一些新属性出现。 例如第 4 行,已找不到 [req, res] 属性,该属性对应的是客户端浏览器的 HTTP 请求以及服务器的 HTTP 响应。
10.6. 客户端的 [index] 页面
客户端的 [index] 页面生成以下日志:
- 第 4 行:对象 [this.$nuxt] 的属性。这是一个包含 51 个属性的丰富对象;
- 第 6 行:对象 [this.$nuxt.context] 的属性。其属性与客户端插件中的对象 [context] 相同;