koa api学习笔记 (一) 基于Node.js平台开发框架

koa  

koa主要是基于Node.js的平台开发的下一代web框架,由Express幕后的原班人马打造,用于编写服务端应用程序。

附上官方文档地址:https://koa.bootcss.com/#

一、安装支持koa以来node v7.6.0或ES2015及更高版本和async方法

node安装方法:
$ nvm install 7
$ npm i koa
$ node my-koa-app.js

二、.应用程序及特点:

koa体积小;

没有捆绑中间件,应用程序包含一组中间件函数的对象;

低级中间件层中提供了高级“语法糖”,提高了互操作性和稳健性;

提供常见的任务方法 诸如内容协商,缓存清理,代理支持和重定向等。

例如:hello Word 应用
const Koa = require('koa');
const app = new Koa();

app.use(async ctx => {
    ctx.body = 'hello word';
});

app.listen(3000);

1.koa级联:使用async功能可以实现“真实”的中间件,调用“下游”,然后控制流回“上游”。

请求开始时会一次穿过中间件,然后继续移交控制给response中间件,当有中间件调用next()则该函数暂停并将控制传递给定义的下一个中间件。当在下游没有更多的中间件执行后,堆栈将展开并且每个中间件恢复执行其上游行为。

2.设置

应用程序设置是app实例上的属性

将设置传递给构造函数
const Koa = require('koa');
const app = new Koa({ proxy: true });

动态形式
const Koa = require('koa');
const app = new Koa();
app.proxy = true;

3.app.listen(...)

可以将一个或多个koa应用程序安装在一起形成具有单个HTTP服务器的更大应用程序。给定的参数传递给Server#listen(),可以参考nodejs文档中的:http://nodejs.cn/api/net.html#net_server_listen ;app.listen(...)方法可以将同一个应用程序同时作为HTTP和HTTPS或多个地址。

const http = require('http');
const https = require('https');
const Koa = require('koa');
const app = new Koa();
http.createServer(app.callback()).listen(3000);
https.createServer(app.callback()).listen(3001);

 

补充知识点:语法糖是什么?

       语法糖:(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。

4.app.callback()

返回适用于 http.createServer() 方法的回调函数来处理请求。也可以使用此回调函数将 koa 应用程序挂载到 Connect/Express 应用程序中。

5.app.use(function)

        将给定的中间件方法添加到此应用程序。app.use()返回this,可以链式表达。

app.use(someMiddleware)
app.use(someOtherMiddleware)
app.listen(3000)
上面的代码等同于下面的代码
app.use(someMiddleware)
   .use(someOtherMiddleware)
   .listen(3000)

6.app.keys=

设置签名的Cookie秘钥。

举例,以下是可以接受的:
app.keys = ['im a newer secret', 'i like turtle'];
app.keys = new KeyGrip(['im a newer secret', 'i like turtle'], 'sha256');

这些密钥可以倒换,并在使用 { signed: true } 参数签名 Cookie 时使用

ctx.cookies.set('name', 'tobi', { signed: true });

7.app.context

         app.context是创建ctx的原型,可以通过编辑app.context为ctx添加其他属性。这对于将 ctx 添加到整个应用程序中使用的属性或方法非常有用,这可能会更加有效(不需要中间件)和/或 更简单(更少的 require()),而更多地依赖于ctx,这可以被认为是一种反模式。

例如,要从ctx添加对数据库的引用:

app.context.db = db();

app.use(async ctx => {
  console.log(ctx.db);
});

注意:安装的应用程序目前使用其父级的 ctx 和设置。 因此,安装的应用程序只是一组中间件。

三、上下文(Context)

Koa Context是将node的request和response对象封装到单个对象中,为编写web应用程序和API提供很多有用的方法。这些操作在HTTP服务器开发中频繁使用,它们被添加到此级别而不是更高级别的框架,这将强制中间件重新实现此通用功能。每个请求都将创建一个 Context,并在中间件中作为接收器引用,或者 ctx 标识符。如下所示

app.use(async ctx => {
    ctx; // 这是 Context
    ctx.request; // 这是 koa Request
    ctx.response; // 这是 koa Response
});

为方便起见许多上下文的访问器和方法直接委托给它们的 ctx.request或 ctx.response ,不然的话它们是相同的。 例如 ctx.type 和 ctx.length 委托给 response 对象,ctx.path 和 ctx.method 委托给 request

API 

Context 具体方法和访问器:

ctx.req:Node 的 request 对象.

ctx.res:Node 的 response 对象.
绕过 Koa 的 response 处理是 不被支持的. 应避免使用以下 node 属性:
    res.statusCode
    res.writeHead()
    res.write()
    res.end()

ctx.request:koa 的 Request 对象.

ctx.response:koa 的 Response 对象.

ctx.state:推荐的命名空间,用于通过中间件传递信息和你的前端视图。
ctx.state.user = await User.find(id);

ctx.app:应用程序实例引用

ctx.app.emit:ctx.app.emit 发出一个类型由第一个参数定义的事件

ctx.cookies.get(name, [options]):
    通过 options 获取 cookie name:
        signed 所请求的cookie应该被签名
    koa 使用 cookies 模块,其中只需传递参数。 

ctx.cookies.set(name, value, [options]):通过 options 设置 cookie name 的 value :   
    maxAge: 一个数字, 表示从 Date.now() 得到的毫秒数.
        expires: 一个 Date 对象, 表示 cookie 的到期日期 (默认情况下在会话结束时过期).
        path: 一个字符串, 表示 cookie 的路径 (默认是/).
        domain: 一个字符串, 指示 cookie 的域 (无默认值).
        secure: 一个布尔值, 表示 cookie 是否仅通过 HTTPS 发送 (HTTP 下默认为 false, HTTPS 下默认为 true). 阅读有关此参数的更多信息.
        httpOnly: 一个布尔值, 表示 cookie 是否仅通过 HTTP(S) 发送,, 且不提供给客户端         JavaScript (默认为 true).
        sameSite: 一个布尔值或字符串, 表示该 cookie 是否为 "相同站点" cookie (默认为 false). 可以设置为 'strict', 'lax', 'none', 或 true (映射为 'strict').
        signed: 一个布尔值, 表示是否要对 cookie 进行签名 (默认为 false). 如果为 true, 则还会发送另一个后缀为 .sig 的同名 cookie, 使用一个 27-byte url-safe base64 SHA1 值来表示针对第一个 Keygrip 键的 cookie-name=cookie-value 的哈希值. 此签名密钥用于检测下次接收 cookie 时的篡改.
        overwrite: 一个布尔值, 表示是否覆盖以前设置的同名的 cookie (默认是 false). 如果是     true, 在同一个请求中设置相同名称的所有 Cookie(无论路径或域)是否在设置此Cookie 时从 Set-Cookie 消息头中过滤掉.

ctx.throw([status], [msg], [properties]):抛出一个包含.status的属性错误方法,默认500,koa做出适当响应。允许一下组合:
    ctx.throw(400);
    ctx.throw(400, 'name required');
    ctx.throw(400, 'name required', {user: user});
例如:ctx.throw(400, 'name required')等效于:
const err = new Error('name required');
err.status = 400;
err.expose = true;
throw err;

ctx.respond: 为了绕过koa的内置response处理,使用原始的res对象不用koa处理response时使用此参数。(注意:koa不支持此功能,这可能会破坏koa的中间件和koa本身的预期功能)

Request别名:下面的访问器和request别名等效:

ctx.header
ctx.headers
ctx.method
ctx.method=
ctx.url
ctx.url=
ctx.originalUrl
ctx.origin
ctx.href
ctx.path
ctx.path=
ctx.query
ctx.query=
ctx.querystring
ctx.querystring=
ctx.host
ctx.hostname
ctx.fresh
ctx.stale
ctx.socket
ctx.protocol
ctx.secure
ctx.ip
ctx.ips
ctx.subdomains
ctx.is()
ctx.accepts()
ctx.acceptsEncodings()
ctx.acceptsCharsets()
ctx.acceptsLanguages()
ctx.get()

Response别名: 下面的访问器和response别名等效:

ctx.body
ctx.body=
ctx.status
ctx.status=
ctx.message
ctx.message=
ctx.length=
ctx.length
ctx.type=
ctx.type
ctx.headerSent
ctx.redirect()
ctx.attachment()
ctx.set()
ctx.append()
ctx.remove()
ctx.lastModified=
ctx.etag=

四、请求

       koa Request 对象是在node的原生请求对象之上的抽象,提供了诸多对HTTP服务器开发有用的功能。

API

request.header 请求头

request.header= 设置请求头对象

request.headers 请求头对象,别名为request.header

request.headers= 设置请求头对象,别名为 request.header=

request.method 请求方法

request.method= 设置请求方法,对部分中间件有用

request.length 返回以数字返回请求的Content-Length 或 undefined

request.url 获取请求URL

request.url= 设置请求URL,对url重写有用

request.originalUrl 获取请求原始URL

request.origin 获取URL的来源,包括protocol和host
ctx.request.origin
//=>http://example.com

request.href 获取完整的请求URL,包括protocol,host和url
ctx.request.href;
//=>http://example.com/foo/bar?q=1

request.path 获取请求路径名

request.path= 设置请求路径名,并在存在时保留查询字符串

request.querystring 根据?获取原始查询字符串

request.querystring= 设置原始查询字符串

request.search 使用?获取原始查询字符串

request.search= 设置原始查询字符串

request.host 存在时获取主机(hostname:port)当 app.proxy 是 true 时支持 X-Forwarded-Host,否则使用 Host。

request.hostname 存在时获取主机名。当 app.proxy 是 true 时支持 X-Forwarded-Host,否则使用 Host。

request.URL 获取WHATWG解析的URL对象。

request.type 获取请求Content-Type,不含“charset”等参数
const ct = ctx.request.type;
// => "image/png"

request.charset 存在时获取请求字符集,或者undefined
ctx.request.charset;
// => "utf-8"

request.query 获取解析的查询字符串,当没有查询字符串时,返回一个空对象。请注意,此 getter _不_ 支持嵌套解析。
例如 "color=blue&size=small":
{
color: 'blue',
size: 'small'
}

request.query= 讲查询字符串设置为给定对象,此setter不支持嵌套对象
ctx.query = {next: '/login'};

request.fresh 检查请求缓存是否“新鲜”,也就是内容没有改变。此方法用于 If-None-Match / ETag, 和 If-Modified-Since 和 Last-Modified 之间的缓存协商。 在设置一个或多个这些响应头后应该引用它。
//新鲜度检查需要状态20x或304
ctx.status = 200;
ctx.set('ETag', '123');
//缓存是好的
if(ctx.fresh){
ctx.status = 304;
return;
}
//缓存是陈旧的
//获取新数据
ctx.body = await db.find('something');

request.state 与request.fresh 相反

request.protocol 返回请求协议,“https”或“http”。当app.proxy是true时支持X-Forwarded-Proto

request.secure 通过ctx.protocol == "https"来检查请求是否通过TLS发出

request.ip 请求远程地址。当app.proxy是true时支持X-Forwarded-Proto

request.ips 当 X-Forwarded-For 存在并且 app.proxy 被启用时,这些 ips 的数组被返回,从上游 - >下游排序。 禁用时返回一个空数组。

request.subdomains 以数组的形式返回子域
子域是应用程序主域之前主机的点分隔部分。默认情况下,应用程序的域名假定为主机的最后两个部分。这可以通过设置 app.subdomainOffset 来更改。

request.is(types...) 检查传入请求是否包含 Content-Type 消息头字段, 并且包含任意的 mime type。 如果没有请求主体,返回 null。 如果没有内容类型,或者匹配失败,则返回 false。 反之则返回匹配的 content-type。

内容协商

koa的request对象包括由accepts和negotiator提供的内容协商实用函数。

这些实用函数是:
request.accepts(types)
检查给定的 type(s) 是否可以接受,如果 true,返回最佳匹配,否则为 false。 type 值可能是一个或多个 mime 类型的字符串,如 application/json,扩展名称如 json,或数组 ["json", "html", "text/plain"]。
根据需要多次调用 ctx.accepts(),或使用 switch:
switch (ctx.accepts('json', 'html', 'text')) {
  case 'json': break;
  case 'html': break;
  case 'text': break;
  default: ctx.throw(406, 'json, html, or text only');
}



request.acceptsEncodings(types)
request.acceptsEncodings(encodings)
检查 encodings 是否可以接受,返回最佳匹配为 true,否则为 false。 请注意,您应该将identity 作为编码之一!
当没有给出参数时,所有接受的编码将作为数组返回:
// Accept-Encoding: gzip, deflate
ctx.acceptsEncodings();
// => ["gzip", "deflate", "identity"]
注意,如果客户端显式地发送 identity;q=0,那么 identity 编码(这意味着没有编码)可能是不可接受的。 虽然这是一个边缘的情况,你仍然应该处理这种方法返回 false 的情况。


request.acceptsCharsets(charsets) 
检查 charsets 是否可以接受,在 true 时返回最佳匹配,否则为 false。
// Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5
ctx.acceptsCharsets('utf-8', 'utf-7');
// => "utf-8"
ctx.acceptsCharsets(['utf-7', 'utf-8']);
// => "utf-8"
当没有参数被赋予所有被接受的字符集将作为数组返回:
// Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5
ctx.acceptsCharsets();
// => ["utf-8", "utf-7", "iso-8859-1"]



request.acceptsLanguages(langs)
检查 langs 是否可以接受,如果为 true,返回最佳匹配,否则为 false。
// Accept-Language: en;q=0.8, es, pt
ctx.acceptsLanguages('es', 'en');
// => "es"

ctx.acceptsLanguages(['en', 'es']);
// => "es"
当没有参数被赋予所有接受的语言将作为数组返回:
// Accept-Language: en;q=0.8, es, pt
ctx.acceptsLanguages();
// => ["es", "pt", "en"]


request.idempotent  检查请求是否是幂等的。


request.socket  返回请求套接字。

request.get(field)  返回请求头(header), field 不区分大小写.



如果没有提供类型,则返回所有可接受的类型。

如果提供多种类型,将返回最佳匹配。 如果没有找到匹配项,则返回一个false,你应该向客户端发送一个406 "Not Acceptable" 响应。

如果接收到任何类型的接收头,则会返回第一个类型。 因此,你提供的类型的顺序很重要。

五、响应(Response)

Koa Response 对象是在 node 的原生响应对象之上的抽象,提供了诸多对 HTTP 服务器开发有用的功能。

API

response.header 响应头对象。

response.headers 响应头对象。别名是 response.header。

response.socket  响应套接字。 作为 request.socket 指向 net.Socket 实例。

response.status 获取响应状态。默认情况下,response.status 设置为 404 而不是像 node 的 res.statusCode 那样默认为 200。

response.status= 通过数字代码设置响应状态
由于 response.status 默认设置为 404,因此发送没有 body 且状态不同的响应的操作如下:
ctx.response.status = 200;
// 或其他任何状态
ctx.response.status = 204;

response.message 获取响应的状态消息. 默认情况下, response.message 与 response.status 关联.

response.message=  将响应的状态消息设置为给定值。

response.length=  将响应的 Content-Length 设置为给定值。

response.length  以数字返回响应的 Content-Length,或者从ctx.body推导出来,或者undefined。

response.body  获取响应主体。

response.body=  将响应体设置为以下之一:
string 写入
Buffer 写入
Stream 管道
Object || Array JSON-字符串化
null 无内容响应
如果 response.status 未被设置, Koa 将会自动设置状态为 200 或 204。
Koa 没有防范作为响应体的所有内容 - 函数没有有意义地序列化,返回布尔值可能会根据您的应用程序而有意义。并且当错误生效时,它可能无法正常工作 错误的属性无法枚举。 我们建议在您的应用中添加中间件,以确定每个应用的正文类型。 示例中间件可能是:
app.use(async (ctx, next) => {
  await next()
  ctx.assert.equal('object', typeof ctx, 500, '某些开发错误')
})

String  
Content-Type 默认为 text/html 或 text/plain, 同时默认字符集是 utf-8。Content-Length 字段也是如此。

Buffer 
Content-Type 默认为 application/octet-stream, 并且 Content-Length 字段也是如此。

Stream
Content-Type 默认为 application/octet-stream。
每当流被设置为响应主体时,.onerror 作为侦听器自动添加到 error 事件中以捕获任何错误。此外,每当请求关闭(甚至过早)时,流都将被销毁。如果你不想要这两个功能,请勿直接将流设为主体。
以下是流错误处理的示例,而不会自动破坏流:
const PassThrough = require('stream').PassThrough;
app.use(async ctx => {
  ctx.body = someHTTPStream.on('error', (err) => ctx.onerror(err)).pipe(PassThrough());
});

Object
Content-Type 默认为 application/json. 这包括普通的对象 { foo: 'bar' } 和数组 ['foo', 'bar']。

response.get(field)  不区分大小写获取响应头字段值 field。
const etag = ctx.response.get('ETag');

response.has(field) 如果当前在响应头中设置了由名称标识的消息头,则返回 true. 消息头名称匹配不区分大小写.
const rateLimited = ctx.response.has('X-RateLimit-Limit');

response.set(field, value)  设置响应头 field 到 value:
ctx.set('Cache-Control', 'no-cache');

response.append(field, value)  用值 val 附加额外的消息头 field。
ctx.append('Link', '<http://127.0.0.1/>');

response.set(fields)  用一个对象设置多个响应头fields:
ctx.set({
  'Etag': '1234',
  'Last-Modified': date
});

response.remove(field)  删除消息头 field。

response.type  获取响应 Content-Type, 不含 "charset" 等参数。
const ct = ctx.type;
// => "image/png"

response.type=  设置响应 Content-Type 通过 mime 字符串或文件扩展名
ctx.type = 'text/plain; charset=utf-8';
ctx.type = 'image/png';
ctx.type = '.png';
ctx.type = 'png';

response.is(types...)  非常类似 ctx.request.is(). 检查响应类型是否是所提供的类型之一。这对于创建操纵响应的中间件特别有用。
例如, 这是一个中间件,可以削减除流之外的所有HTML响应。
const minify = require('html-minifier');
app.use(async (ctx, next) => {
  await next();
  if (!ctx.response.is('html')) return;
  let body = ctx.body;
  if (!body || body.pipe) return;
  if (Buffer.isBuffer(body)) body = body.toString();
  ctx.body = minify(body);
});

response.redirect(url, [alt])
执行 [302] 重定向到 url.
字符串 “back” 是特别提供 Referrer 支持的,当 Referrer 不存在时,使用 alt 或 “/”。
ctx.redirect('back');
ctx.redirect('back', '/index.html');
ctx.redirect('/login');
ctx.redirect('http://google.com');

要更改 “302” 的默认状态,只需在该调用之前或之后给 status 赋值。要变更主体请在此调用之后:
ctx.status = 301;
ctx.redirect('/cart');
ctx.body = 'Redirecting to shopping cart';

response.attachment([filename], [options])  将 Content-Disposition 设置为 “附件” 以指示客户端提示下载。(可选)指定下载的 filename 和部分参数

response.headerSent  检查是否已经发送了一个响应头。 用于查看客户端是否可能会收到错误通知。

response.lastModified  将 Last-Modified 消息头返回为 Date, 如果存在。

response.lastModified=  将 Last-Modified 消息头设置为适当的 UTC 字符串。您可以将其设置为 Date 或日期字符串。
ctx.response.lastModified = new Date();

response.etag=  设置包含 " 包裹的 ETag 响应, 请注意,没有相应的 response.etag getter。
ctx.response.etag = crypto.createHash('md5').update(ctx.body).digest('hex');

response.vary(field)  设置 field 的 vary。

response.flushHeaders()  刷新任何设置的消息头,然后是主体(body)。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值