Koa与Node.js开发实战
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.2 Context对象

Koa中有一个非常重要的概念叫上下文。怎么理解这个上下文的意思呢?例如,有人在聊天群里说:“快看窗外,下雪啦!”你跑到窗口一看,艳阳高照,怎么回事?赶紧去看聊天记录,原来发信息的人在北方,虽然现在是10月,而你却在南方。这里的“北方”“10月”就是这次对话的上下文。如果没有上下文,就无法准确定义这次对话。类似地,一次请求会包含用户的登录状态,或者一些Token之类的信息,这些信息就是上下文的一部分,用于确定一次请求的环境。

2.2.1 什么是Context对象

Koa将Node.js的Request(请求)和Response(响应)对象封装到Context对象中,所以也可以把Context对象称为一次对话的上下文,通过加工Context对象,就可以控制返回给用户的内容。

Context对象还内置了一些常用属性,如context.state、context.app、context.cookies、context.throw等,也可以在Context对象中自定义一些属性、配置以供全局使用。

Koa应用程序中的每个请求都将创建一个Context,并在中间件中被作为参数引用,代码如下:

上述代码演示了如何访问Context对象。也可以使用this关键字访问Context对象。下一节会介绍Context对象中常用的属性和方法,为学习后面的知识打好基础。

2.2.2 常用属性和方法

Koa的上下文中包含了很多属性和方法,通过这些属性和方法能够实现很多功能,如路由控制、读取Cookie、返回内容给用户等。

1.ctx.request

ctx是context的简写,ctx.request是Koa的Request对象,Koa的Request对象是在Node.js的请求对象之上的抽象,提供了很多对HTTP服务器开发有用的功能。如果要访问Request对象,可以调用ctx.req。ctx.request对象还有哪些属性呢?首先来看下面这段代码:

上述代码主要的功能是获取GET请求中的参数。把以上代码复制到app.js中,然后在命令行中输入如下指令:

随后在浏览器中访问http://localhost:3000/?search=koa&keywords=context,便可以看到一串字符串,如下所示:

假如要使用search这个参数,可以直接通过query.search来获取。

POST请求的参数获取方式和GET请求不同。Koa没有封装获取POST请求参数的方法,因此需要解析Context中的原生Node.js请求对象req,代码如下:

把上述代码复制到app.js中,替换原来的代码,然后按“Ctrl+C”组合键停止服务器,再执行如下命令重启服务器:

接着打开一个新的命令行窗口,执行如下命令:

curl命令可以模拟POST请求,-d参数后面是POST请求的参数。执行完成后切换回原来的命令行窗口,就能看到console.log命令打印出来的如下字符串:

除此以外,还可以通过koa-bodyparser等中间件来获取POST请求的参数,而且更加方便。这部分会在后面的中间件章节中详细介绍,此处不再赘述。

下面介绍一下如何使用ctx.request处理路由,代码如下:

在上述代码中,首先通过ctx.request.method来判断请求是GET还是POST,如果是GET请求,再通过ctx.request.path来判断该请求的具体路径是否为根路径。如果是根路径就显示“Hello World”,如果不是就显示一个连接,单击之后访问根路径即可。这是一个非常简单的处理方式,实际开发中可以利用koa-router这个中间件来处理路由。

2.ctx.response

ctx.response是Koa的Response对象。Koa的Response对象是在Node.js的原生响应对象之上的抽象,提供了很多对HTTP服务器开发有用的功能。

之前在介绍ctx.request对象的时候也使用了ctx.response.body这个属性,用于设置返回给用户的响应主体。之前使用的响应主体类型以String写入。

在实际开发中,除设置一个请求的响应主体外,往往还需要通过ctx.response.status设置请求状态,如200、404、500等。通过ctx.response.type可以设置响应的Content-Type,如果响应内容是HTML格式,则设置为ctx.response.type = 'html';如果响应内容是一张png图片,则设置为ctx.response.type = 'image/png'。显式地设置Content-Type是因为浏览器默认的Content-Type是text/plain,如果Content-Type不对会发生解析错误。接下来将通过一个例子来展示这些属性的使用方法,代码如下:

在上述代码中,首先通过ctx.response.status设置请求的状态码,然后通过ctx.request.accepts()函数来判断客户端期望的数据类型,再通过ctx.response.type设置响应的数据类型,最后通过ctx.response.body设置响应体内容。和ctx.request.accepts()类似的一个方法是ctx.response.is(types...),它可以用来检查响应类型是否是所提供的类型之一,这对创建操纵响应的中间件特别有用。

还有一个比较常用的方法是ctx.response.redirect(url, [alt]),这个方法用于将状态码302重定向到URL,例如用户登录后自动重定向到网站的首页。

3.ctx.state

ctx.state是推荐的命名空间,用于通过中间件传递信息和前端视图。类似koa-views这些渲染View层的中间件也会默认把ctx.state里面的属性作为View的上下文传入。

上述代码是把user属性存放到ctx.state对象里,以便能够被另一个中间件读取。

4.ctx.cookies

ctx.cookies用于获取和设置Cookie。

其中options的配置见表2.1。

表2.1 options的配置

5.ctx.throw

ctx.throw用于抛出错误,把错误信息返回给用户,代码示例如下:

运行这段示例代码,会在页面上看到一个状态码为500的错误页“Internal Server Error”。