使用node搭建本地http服务,Koa只是选择之一。上半年看了个新闻,express的占有率又处于上升。
安装
npm install koa
复制代码
快速上手
创建一个文件koa.js
,贴入以下代码:
const Koa = require('koa')
const app = new Koa()
app.use((ctx) => {
ctx.body = '<h1>Hello Koa</h1>'
ctx.type = 'text/html'
})
const port = 3001
app.listen(port, () => {
console.log(`Koa start at http://127.0.0.1:${port}`)
})
复制代码
然后运行该脚本
% node koa.js
Koa start at http://127.0.0.1:3001
复制代码
打开http://127.0.0.1:3001
,即可看到Hello Koa
的大黑字。
搭建本地 GET
POST
测试服务器
基于上面的代码,做一下改造。出于简单和触及基础的考虑,这里我们不使用koa-router
等其他中间件。
PS:后面课程对本篇有依赖
识别 GET | POST
const { url, method } = ctx.request
复制代码
这里的method
,即http
请求方法,url
则是请求的绝对路径。
用method驱动响应逻辑
app.use((ctx) => {
const { url, method } = ctx.request
if(method === 'POST') {
// 这里配置POST响应
} else {
ctx.body = `Hello Koa`
}
ctx.type = 'text/plain'
})
复制代码
读取ctx.req流
在app.use
使用中间件,会传入ctx
上下文对象作为第一个参数;其中的ctx.req
就是客户端写入的流。
按HTTP规范,GET
并不会写请求流,POST
会,也就是我们post的表单、上传文件等数据。
流的读取是异步,不过可以统一处理。我们先写一个流读取的方法,封装为Promise
:
const readStream = (stream) => new Promise((resolve, reject) => {
const chunks = []
stream.on('data', chunk => {
chunks.push(chunk)
})
stream.on('end', () => {
const buff = Buffer.concat(chunks)
const data = buff.toString('utf-8')
resolve(data)
})
stream.on('error', err => {
reject(err)
})
})
复制代码
一般来讲,使用data
end
error
这3个生命周期基本够用。
由于读取是按block来读取,所以一个大文件或者数据,会有多次data
生命周期触发。由此可以发散联想:http
基于ip/tcp
协议,是按序发送数据包,所以chunks
缓存区使用数组结构,有序推入、合成即可。
合成服务
最终代码
const Koa = require('koa')
const port = 3001
const app = new Koa()
const readStream = (stream) => new Promise((resolve, reject) => {
const chunks = []
stream.on('data', chunk => {
chunks.push(chunk)
})
stream.on('end', () => {
const buff = Buffer.concat(chunks)
const data = buff.toString('utf-8')
resolve(data)
})
stream.on('error', err => {
reject(err)
})
})
app.use(async (ctx) => {
const { url, method } = ctx.request
if(method === 'POST') {
try {
const data = await readStream(ctx.req)
console.log(`[${method}]`, data)
ctx.body = data
} catch(err) {
ctx.status = 500
ctx.body = err
}
} else {
ctx.body = `${decodeURIComponent(url)}`
console.log(`[${method}]`, url)
}
ctx.type = 'text/plain'
})
app.listen(port, () => {
console.log(`Koa start at http://127.0.0.1:${port}`)
})
复制代码
单元测试
安装jest
和axios
npm i -D jest axios
复制代码
创建koa.test.js
文件
const axios = require('axios')
describe('Koa service get', () => {
it(`get /123`, done => {
axios.get(`http://127.0.0.1:3001/123`).then(({ data }) => {
expect(data).toEqual('/123')
done()
})
})
})
describe('Koa service get', () => {
it(`get /?123`, done => {
axios.get(`http://127.0.0.1:3001/?123`).then(({ data }) => {
expect(data).toEqual('/?123')
done()
})
})
})
describe('Koa service get', () => {
it(`get /中文`, done => {
axios.get(`http://127.0.0.1:3001/${encodeURIComponent('中文')}`).then(({ data }) => {
expect(data).toEqual('/中文')
done()
})
})
})
describe('Koa service get', () => {
it(`get /?中文`, done => {
axios.get(`http://127.0.0.1:3001/?${encodeURIComponent('中文')}`).then(({ data }) => {
expect(data).toEqual('/?中文')
done()
})
})
})
describe('Koa service post', () => {
it(`post '中文'`, done => {
axios.post(`http://127.0.0.1:3001/`, '中文').then(({ data }) => {
expect(data).toEqual('中文')
done()
})
})
})
describe('Koa service post', () => {
it(`post 'AbC'`, done => {
axios.post(`http://127.0.0.1:3001/`, 'AbC').then(({ data }) => {
expect(data).toEqual('AbC')
done()
})
})
})
复制代码
更改package.json
{
"scripts": {
"test": "jest"
}
}
复制代码
运行单元测试
% npm test
> testnpm@1.0.0 test
> jest
PASS ./koa.test.js
Koa service get
✓ get /123 (26 ms)
✓ get /?123 (2 ms)
✓ get /中文 (2 ms)
✓ get /?中文 (2 ms)
Koa service post
✓ post '中文' (2 ms)
✓ post 'AbC' (2 ms)
Test Suites: 1 passed, 1 total
Tests: 6 passed, 6 total
Snapshots: 0 total
Time: 0.266 s, estimated 1 s
Ran all test suites.
复制代码
以上
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END