使用 Koa 搭建前端服務


環境准備

  1. node 環境

Koa 依賴 node v7.6.0 或 ES2015及更高版本和 async 方法支持,我本地的node環境為 v14.4.0

image

快速開始

使用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

終端如下,記住之后每次添加依賴后都需要重啟服務:

image

此時在瀏覽器中訪問該地址后,可看到打印出的 “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:9999http://127.0.0.1:9999/index,http://127.0.0.1:9999/todo 都可以進入對應頁面
效果:

image

現在可以訪問文件內容了,但是本地靜態資源卻不能訪問,這時 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');
}) 

重啟后文件訪問到啦,此時所有文件都作為靜態資源訪問,所以進入子頁面時需要帶全文件名稱,否則是訪問不到的呢~

image

有沒有發現,如果依靠 ctx.request.url 手動處理路由,將會寫很多處理代碼,這時候就需要對應的路由的中間件對路由進行控制,這里介紹一個比較好用的路由中間件 koa-router (由於目標項目中使用的是單頁面應用,所以這里暫不多介紹)

$ npm install koa-router@7 -S

此時可以上手我們的項目了,把已寫好的項目打包完成並替換 dist 文件
可以看到已經訪問到項目主頁了~

image

此時發現一個問題,當再次刷新的時候,竟然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) 

image

使用 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:

  1. 如果習慣使用 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"
    },
    
  2. koa2與koa1的最大區別是koa2實現異步是通過async/awaite,koa1實現異步是通過generator/yield,而express實現異步是通過回調函數的方式。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM