前言 不會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來做數據聚合,從幾個介面中拼接數據供前端使用,而不需要為數據結構和數據內容煩惱,並且你不用擔心效率,因為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
寫在最後
本文通過路由中間件簡單實現介面,模塊化管理介面文件,還對介面進行跨域處理。
主要還是玩模塊,通過模塊可以組合出適合自己業務的系統。