前言
不會node.js的前端不是一個好前端!
這幾年node.js確實是越來越火了,好多公司對node.js都開始有要求。雖說前端不一定要會后端,但想要成為一個優秀的前端,node.js是必經之路。
我對於node.js的第一印象,認為它是一門后端語言,只是前端學習起來成本會更低更好上手。慢慢經過了解后,使用node.js寫接口對於前端來說很方便,但不僅限於寫接口。在一些大公司里,node.js並不是開發接口的首選目標,而是作為中間層來使用。我們都知道分工合作,讓專業的人做更專業的事,工作效率會大大提高。node.js作為中間層的存在,可以讓后端更專注於寫接口和管理數據。
試想一下,現在由於業務邏輯改變,后端需要對數據接口進行更改,是否會花費時間?如果你會node.js,那么你就可以通過node.js來做數據聚合,從幾個接口中拼接數據供前端使用,而不需要為數據結構和數據內容煩惱,並且你不用擔心效率,因為node.js天生異步。
包括我們常用的一些腳手架工具也是基於node.js環境搭建,你甚至還可以使用node.js來做數據挖掘,也就是我們所說的爬蟲,node.js的應用層面還有很多。以上都是我了解到的一些信息。
目前node.js比較主流框架分為express、koa、egg。koa作為新一代的框架,由開發express的原班人馬打造,支持ES7 async/await,拋棄回調函數,在寫法上更自然。koa沒有綁定任何中間件,關鍵的設計點是在其低級中間件層中提供高級“語法糖”,koa的體積也因此更小。(中間件在koa中是一個很重要的存在,在后面我會着重去學習它)
接下來,我要開始koa入坑之路。
koa初體驗
hello,koa!
安裝koa ,npm i koa
創建一個app.js,命令行執行 node app
const Koa = require('koa' ); const app = new Koa(); app.context.msg = 'Hello Koa!' app.use(async ctx => { ctx.body = ctx.msg; }); app.listen( 3000);
app.context 為執行上下文添加屬性和方法
app.use 將給定的中間件方法添加到應用程序中
該方法接收ctx和next作為參數,ctx 是執行上下文,里面存儲了request和response等信息,還有ctx.body,我們可以通過它來返回數據,next作為函數調用,將執行權交給下一個中間件執行。
這里我先安裝個nodemon,因為每次更改文件時,都需要重新執行命令以更新代碼,這種重復性的工作就交給模塊來處理。
通過 npm i nodemon 安裝好后,命令行執行 nodemon app,這樣每次更改文件時,nodemon都自動刷新。
Koa-router 路由管理
為了代碼的可維護性,減少代碼量。使用路由管理顯得尤為重要,koa框架也有自己對應的路由管理模塊(koa-router),我們可以通過npm 下載使用。
var Koa = require('koa' ); var Router = require('koa-router' ); var app = new Koa(); var router = new Router(); router.get( '/', (ctx, next) => { ctx.body = 'hello' });
//使用路由中間件 app .use(router.routes()) .use(router.allowedMethods()); app.listen( 3000 )
routes 注冊使用路由
allowedMethods 處理的業務是當所有路由中間件執行完成之后,若 ctx.status 為空或者404的時候,豐富 response 對象的 header 頭,不加問題也不大,官方例子有加上,所以我這里也加了
這時訪問3000端口就可以得到ctx.body 返回的內容
get請求
1. 獲取接口query參數
通過查詢 ctx.request.query 得到get參數, ctx.request.header 得到請求時的頭部信息,ctx.request.method 得到請求方法。這樣可以對應的來做一些判斷,例如請求的參數是否合法,請求方法是否合法。
router.get( '/get', (ctx, next) => { let id = ctx.request.query.id ctx.body = { id, code: 1 } });
2. 命名路由 獲取參數
router.get( '/get/:id', (ctx, next) => { let id = ctx.request.params.id ctx.body = { id, code: 1 } });
例如請求地址為 /get/123,通過 ctx.request.params 獲取參數
這寫法讓我想起了vue-router,設置params可以說是一樣了。
post請求
原生獲取post請求的參數,需要監聽ctx.req的data事件和end事件,分段拼接成完整的字符串,然后還需要切割轉碼。所以在獲取post參數時,我會借助 koa-bodyparser 來減少不必要的操作。
在引入 koa-bodyparser 時,需要注意的是順序問題,使用 koa-bodyparser 需要放在使用路由之前,這是由於中間件執行順序的原因(暫且理解為 bodyparser 經過處理,把處理好的值轉交到路由)
var bodyParser = require('koa-bodyparser'); app.use(bodyParser()); app .use(passport.initialize()) .use(passport.session())
借助中間件koa-bodyparser,訪問 ctx.request.body 得到post參數
通過 ctx.set 設置返回頭,設置多個時可傳入對象
router.post('/post', ctx=>{
//設置允許跨域
ctx.set('Access-Control-Allow-Origin','*') ctx.body = { code:1, postParams:ctx.request.body } })
路由模塊化管理
試想一下,現在文件中寫有多個接口,我們在開發和調試起來都會特別麻煩,浪費時間。為了更好的管理接口,現在需要把接口按照功能抽離出來,封裝到一個個的JS文件中,並存放到routes文件夾下。
例如,創建 user.js 來存放用戶相關的接口
const Router = require('koa-router') const route = new Router() const jwt = require('jsonwebtoken') route.get('/getToken', async (ctx)=>{ let {name,id} = ctx.query if(!name && !id){ ctx.body = { msg:'不合法', code:0 } return } //生成token
let token = jwt.sign({name,id},'secret',{ expiresIn: '1h' }) ctx.body = { token: token, code:1 } }) route.get('/getUser', async ctx=>{ let id = ctx.query.id ctx.body = { user:ctx.payload, id, code:1 } }) route.get('/getAllUser', async ctx=>{ let type = ctx.query.type if(type){ ctx.body = { type, code:1 } }else{ ctx.body = { msg:'缺少參數type', code:0 } } }) module.exports = route
以上代碼,將寫好的接口暴露出去,供app.js注冊使用
app.js代碼(部分代碼省略)
let urls = fs.readdirSync(__dirname + '/routes') urls.forEach((element) => { //routes里的js接口文件
let module = require(__dirname + '/routes/' + element) //routes里的文件名作為 路由名
router.use('/' + element.replace('.js', ''), module.routes()) }) //使用路由
app.use(router.routes()).use(router.allowedMethods()) app.listen(3000)
以上代碼,我大概講下流程
1. fs文件模塊讀取routes文件夾目錄內容(獲得的是一個文件名的數組)
2. 數組遍歷,引入接口文件,將文件名作為路由名,注冊使用路由
將 user.js 作為例子,user.js 內有一個 getUser 的接口,我訪問的api地址為 /user/getUser
頭部信息處理
在前后端交互中,頭部信息也是很關鍵的一步,通過對頭部信息的配置,可以對請求作出一些限制,或者是一些優化。
這里我會使用 koa2-cors 為例子,來對跨域做cors處理(部分代碼省略)。
const cors = require('koa2-cors') app.use(cors({ origin: function(ctx) { return 'http://127.0.0.1:5500';//cors
}, exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'], maxAge: 5, credentials: true, allowMethods: ['GET', 'POST'], allowHeaders: ['Content-Type', 'Authorization', 'Accept'], })) app.use(router.routes()).use(router.allowedMethods()) app.listen(3000)
origin : 接受字符串和函數,這里配置的就是允許跨域的域名,如果允許所有域名跨域可傳入 *
allowMethods : 允許請求的方式
allowHeaders : 允許接受的頭部信息
其他的配置選項可以在npm上查看:https://www.npmjs.com/package/koa2-cors
寫在最后
本文通過路由中間件簡單實現接口,模塊化管理接口文件,還對接口進行跨域處理。
主要還是玩模塊,通過模塊可以組合出適合自己業務的系統。
