環境准備
- 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實現異步是通過回調函數的方式。