![Koa与Node.js开发实战](https://wfqqreader-1252317822.image.myqcloud.com/cover/426/25462426/b_25462426.jpg)
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,并在中间件中被作为参数引用,代码如下:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_14.jpg?sign=1739141155-5f1JKASn1j0pCulSwccKcTD1YaeLbNWl-0-c698aa71f9a92ae751c888f8f2d5e2fd)
上述代码演示了如何访问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对象还有哪些属性呢?首先来看下面这段代码:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_15.jpg?sign=1739141155-S5CkuzcTx03z9czwBDsPZksWfKNRJE9B-0-7580483f392ba0946746a7d71d5d99ab)
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_16.jpg?sign=1739141155-dCtcuNEhOgaNZmkpnStlwjiHlmulGFHf-0-fb404fa5af4b0e0aff4e905c2b80fb33)
上述代码主要的功能是获取GET请求中的参数。把以上代码复制到app.js中,然后在命令行中输入如下指令:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_17.jpg?sign=1739141155-HWHFyMCef8xY54lxgVmkNLval0iDuCH5-0-6aee87fbadb142c031f990c445e6f7e3)
随后在浏览器中访问http://localhost:3000/?search=koa&keywords=context,便可以看到一串字符串,如下所示:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_18.jpg?sign=1739141155-Eceg39S9dCpQSY9n4C7Wy2RmbS9JeGkc-0-cef2950e7d711d7c32de5d55027cd9f0)
假如要使用search这个参数,可以直接通过query.search来获取。
POST请求的参数获取方式和GET请求不同。Koa没有封装获取POST请求参数的方法,因此需要解析Context中的原生Node.js请求对象req,代码如下:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_19.jpg?sign=1739141155-R3zfX0kNQlhkQp6xwx9NJS3G3YrAs9dZ-0-a619e8541c6ed0b39e741d4a65a06faf)
把上述代码复制到app.js中,替换原来的代码,然后按“Ctrl+C”组合键停止服务器,再执行如下命令重启服务器:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_20.jpg?sign=1739141155-iiKINKbpXQqGnPxl2l0DZETVfhl6n4IF-0-8f2fb09f9a39ba51d0f093c44b93fb38)
接着打开一个新的命令行窗口,执行如下命令:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_21.jpg?sign=1739141155-YwwNeUomBG53oHbPcYafJcHFiEHskgjK-0-33fbc075d477471673120e217ac7a96c)
curl命令可以模拟POST请求,-d参数后面是POST请求的参数。执行完成后切换回原来的命令行窗口,就能看到console.log命令打印出来的如下字符串:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_22.jpg?sign=1739141155-1nbtLpA7qC2gBm5Y5Eodxo09AmM4YFTx-0-4c2901fbda7a9d83deef1319a7b41e6e)
除此以外,还可以通过koa-bodyparser等中间件来获取POST请求的参数,而且更加方便。这部分会在后面的中间件章节中详细介绍,此处不再赘述。
下面介绍一下如何使用ctx.request处理路由,代码如下:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_23.jpg?sign=1739141155-VwkftUqvsPovSkDYCXAdEYU9qgkNJyVm-0-ababfe286c66267867cec790b8cce184)
在上述代码中,首先通过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不对会发生解析错误。接下来将通过一个例子来展示这些属性的使用方法,代码如下:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_24.jpg?sign=1739141155-rZmZR7LbGi6xKGeDlyDBoQgwYQd7brRe-0-66191156ecd5ab4f37af6ab8300adf92)
在上述代码中,首先通过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的上下文传入。
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_25.jpg?sign=1739141155-Z47cnsicHrPK8WpjE72u1gCypfQnEB2Y-0-9ccaa48d139a8772922ff1a3465f7d19)
上述代码是把user属性存放到ctx.state对象里,以便能够被另一个中间件读取。
4.ctx.cookies
ctx.cookies用于获取和设置Cookie。
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_26.jpg?sign=1739141155-gayOrdZxgNJ4TGOmmErSKfKWvtEYaV5B-0-081252ca51d04cca177299201ba21cf8)
其中options的配置见表2.1。
表2.1 options的配置
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_27.jpg?sign=1739141155-m1kzk4FHX2uqAMwzFtkOcUsU9ovX8oYC-0-a930a30e79d9aad9bf30cedceb863b86)
5.ctx.throw
ctx.throw用于抛出错误,把错误信息返回给用户,代码示例如下:
![](https://epubservercos.yuewen.com/CA5268/13916125705940506/epubprivate/OEBPS/Images/txt003_28.jpg?sign=1739141155-570Y9qbZJFjWNPz7qBXYPkDcYHc8WvgE-0-c5eadeef354d5db37f1b6324e8bb0c47)
运行这段示例代码,会在页面上看到一个状态码为500的错误页“Internal Server Error”。