环境准备
- node 环境
Koa 依赖 node v7.6.0 或 ES2015及更高版本和 async 方法支持,我本地的node环境为 v14.4.0
快速开始
使用koa启动本地静态资源主要需要解决两个问题,一个是使用history路由时,刷新页面使之能正常进入页面,另一个就是请求能正常代理到目标服务,这里如果为了方便可以直接使用 koa 脚手架,也可以自己手动搭建。下面分别介绍一下这两种方法的使用。
从零搭建
① 初始化 package.json
$ npm init
输入该命令后,一路回车,会生成一个package.json文件
② 安装 koa
这里可以在当前目录安装,也可进行以全局安装
// 在当前目录安装
$ npm install koa -S
// 或全局安装
$ npm install koa-generator -g
③ 新建app.js
const Koa = require('koa')
const app = new Koa()
app.use(async ctx => {
ctx.body = 'Hello World';
});
app.listen(9999, () => {
console.log('服务已启动,请访问:http://127.0.0.1:9999 或 localhost:9999');
})
//打开终端
$ node app.js
终端如下,记住之后每次添加依赖后都需要重启服务:
此时在浏览器中访问该地址后,可看到打印出的 “Hello World” 文本,这时一个简单的服务就搭建起来了~
此时服务是启动了,但是浏览器怎么能打印某个文件的内容呢? 首先新建 dist 文件夹,然后建几个文件index.html、todo.html、404.html、img.png
//app.js
const Koa = require('koa')
const app = new Koa()
//要涉及读文件的功能,所以引入node 的 fs 文件系统
const fs = require('fs')
/**
* 用Promise封装异步读取文件方法
* @param {string} page html文件名称
* @return {promise}
*/
function render( page ) {
return new Promise(( resolve, reject ) => {
let distUrl = `./dist/${page}`
fs.readFile(distUrl, "binary", ( err, data ) => {
if ( err ) {
reject( err )
} else {
resolve( data )
}
})
})
}
/**
* 根据URL获取HTML内容
* @param {string} url koa2上下文的url,ctx.url
* @return {string} 获取HTML文件内容
*/
async function route( url ) {
let dist = '404.html'
switch ( url ) {
case '/':
case '/index':
dist = 'index.html'
break
case '/todo':
dist = 'todo.html'
break
case '/404':
dist = '404.html'
break
default:
break
}
let html = await render( dist )
return html
}
app.use(async ctx => {
let url = ctx.request.url
let html = await route( url )
ctx.body = html
});
app.listen(9999, () => {
console.log('服务已启动,请访问:http://127.0.0.1:9999 或 localhost:9999');
})
// dist/index.html 文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>index</title>
</head>
<body>
<h1>koa2 demo index page</h1>
<p>this is a index page</p>
<ul>
<li><a href="/">/</a></li>
<li><a href="/index">/index</a></li>
<li><a href="/todo">/todo</a></li>
<li><a href="/404">/404</a></li>
</ul>
<img src="https://i.loli.net/2021/01/04/UMwA2d1QtKu4cWl.png" alt="" width="100" height="100">
<img src="./img.png" alt="" width="100" height="100">
</body>
</html>
此时访问 http://127.0.0.1:9999,http://127.0.0.1:9999/index,http://127.0.0.1:9999/todo 都可以进入对应页面
效果:
现在可以访问文件内容了,但是本地静态资源却不能访问,这时 koa-static 就可以解决这个问题
$ npm install koa-static -S
//改装 app.js ,将所有文件作为静态资源访问且指向入口 ./dist/index.html上
const Koa = require('koa')
const app = new Koa()
app.use(require("koa-static")(__dirname + "/dist"));
app.listen(9999, () => {
console.log('服务已启动,请访问:http://127.0.0.1:9999 或 localhost:9999');
})
重启后文件访问到啦,此时所有文件都作为静态资源访问,所以进入子页面时需要带全文件名称,否则是访问不到的呢~
有没有发现,如果依靠 ctx.request.url 手动处理路由,将会写很多处理代码,这时候就需要对应的路由的中间件对路由进行控制,这里介绍一个比较好用的路由中间件 koa-router (由于目标项目中使用的是单页面应用,所以这里暂不多介绍)
$ npm install koa-router@7 -S
此时可以上手我们的项目了,把已写好的项目打包完成并替换 dist 文件
可以看到已经访问到项目主页了~
此时发现一个问题,当再次刷新的时候,竟然404!这是因为vue-router使用history模式返回index.html,仅能通过入口文件去加载其子路由。
而koa2的一个中间件,专治SPA应用程序的history模式路由问题,那就是 koa2-connect-history-api-fallback
$ npm install koa2-connect-history-api-fallback -S
//app.js
const Koa = require('koa')
const { historyApiFallback } = require('koa2-connect-history-api-fallback');
const app = new Koa()
app.use(historyApiFallback());
app.use(require("koa-static")(__dirname + "/dist"));
app.listen(9999, () => {
console.log('服务已启动,请访问:http://127.0.0.1:9999 或 localhost:9999');
})
继续测试,发现不管什么路由都可以正常访问到啦~
这时候又遇到问题了,接口请求全部 404,那是因为请求走的都是http://127.0.0.1:9999,那404是必然的啦,那如何把请求代理转发到其他服务器呢? http-proxy-middleware 可以解决这个问题。
$ npm install http-proxy-middleware -S
$ npm i koa2-connect -S
//app.js
const Koa = require('koa')
const Router = require('koa-router')
const { historyApiFallback } = require('koa2-connect-history-api-fallback');
const { createProxyMiddleware } = require('http-proxy-middleware')
const c2k = require('koa2-connect')
const app = new Koa()
app.use(historyApiFallback());
app.use(require("koa-static")(__dirname + "/dist"));
var router = new Router()
var target = 'https://222.222.222.222:8080' // 要代理的目标地址,vue项目写 vue.config.js 里的 target 地址
router.get(
'*',
c2k(
createProxyMiddleware({
target,
changeOrigin: true,
ws: true
})
)
)
app.use(router.routes())
app.listen(9999, () => {
console.log('服务已启动,请访问:http://127.0.0.1:9999 或 localhost:9999');
})
这时发现请求已经代理成功了,GET 请求的 HTTP 码返回了200,但是 POST、PUT 等其它请求方式依旧 404,那是因为咱仅给GET方法添加了target 地址,再将各种方式都补齐:
const Koa = require('koa')
const Router = require('koa-router')
const { createProxyMiddleware } = require('http-proxy-middleware')
const { historyApiFallback } = require('koa2-connect-history-api-fallback');
const c2k = require('koa2-connect')
const app = new Koa()
app.use(historyApiFallback());
app.use(require("koa-static")(__dirname + "/dist"));
var router = new Router()
var target = 'https://abc.com' // 修改成你要代理的目标地址,vue项目写 vue.config.js 里的 target 地址
//项目一共使用5种请求方式: get post put patch delete /* 'head','connect','options','trace','patch' */
let method = ['get', 'post', 'put', 'patch','delete']
method.forEach(item => {
router[item](
'*',
c2k(
createProxyMiddleware({
target,
changeOrigin: true,
ws: true
})
)
)
})
app.use(router.routes())
app.listen(9999)
使用 Koa 搭建前端服务大功告成!如果要用 Koa 脚手架搭建的话更加简单,执行以下命令、再安装上述依赖即可。
$ koa koaServer
总结一下,项目依赖一共包括以下几个:
"dependencies": {
"http-proxy-middleware": "^1.0.6",
"koa": "^2.13.0",
"koa-router": "^7.4.0",
"koa-static": "^5.0.0",
"koa2-connect": "^1.0.2",
"koa2-connect-history-api-fallback": "^0.1.3"
}
tips:
- 如果习惯使用 npm run serve 或者 yarn serve 启动项目的话,可以为 package.json 文件的 scripts 属性添加一条:"serve":"node app.js" 即可
"scripts": { "serve":"node app.js", "test": "echo \"Error: no test specified\" && exit 1" },
- koa2与koa1的最大区别是koa2实现异步是通过async/awaite,koa1实现异步是通过generator/yield,而express实现异步是通过回调函数的方式。