摘要:簡(jiǎn)單入門慣例拿創(chuàng)建應(yīng)用程序作為一個(gè)框架的入門例子。級(jí)聯(lián)應(yīng)用程序是一個(gè)包含一組中間件函數(shù)的對(duì)象,它是按照類似堆棧的方式組織和執(zhí)行的。當(dāng)在下游沒有更多的中間件執(zhí)行后,堆棧將展開并且每個(gè)中間件恢復(fù)執(zhí)行其上游行為。參考資料框架教程
完整Demo地址
里面demo都是自己寫的,保證能跑,至於環(huán)境問題我就不敢保證了。懶得寫就去上面搬走看,懶得搬就直接看文章,大部分代碼連輸出信息都給你們了。
koa-demo
koa 是由 Express 原班人馬打造的,致力于成為一個(gè)更小、更富有表現(xiàn)力、更健壯的 Web 框架。 使用 koa 編寫 web 應(yīng)用,通過組合不同的 generator,可以免除重復(fù)繁瑣的回調(diào)函數(shù)嵌套, 并極大地提升錯(cuò)誤處理的效率。koa 不在內(nèi)核方法中綁定任何中間件, 它僅僅提供了一個(gè)輕量?jī)?yōu)雅的函數(shù)庫(kù),使得編寫 Web 應(yīng)用變得得心應(yīng)手。
前期準(zhǔn)備我們首先安裝一些必要庫(kù)先,根據(jù)個(gè)人選擇可以使用yarn,cnpm,或者npm都行。
KOA框架
yarn add koa
這還不夠,因?yàn)?Koa 依賴 node v7.6.0 或 ES2015及更高版本和 async 方法支持.你們可以根據(jù)自身需要安裝
Babel register
transform-async-to-generator 或 transform-async-to-module-method
因?yàn)槲矣玫?Nodejs10.0,所以不需要安裝這些東西,就不說了。
簡(jiǎn)單入門慣例拿創(chuàng)建應(yīng)用程序作為一個(gè)框架的入門例子。
const Koa = require("koa"), app = new Koa(); app .use(async ctx => { ctx.body = "暗號(hào):Hello World"; }) .listen(3000); console.log("已建立連接,效果請(qǐng)看http://127.0.0.1:3000/");
代碼一目了然,不廢話了。
(完整代碼可以執(zhí)行koa-demo的 lesson1 查看效果)
所謂 favicon,即 Favorites Icon 的縮寫,顧名思義,便是其可以讓瀏覽器的收藏夾中除顯示相應(yīng)的標(biāo)題外,還以圖標(biāo)的方式區(qū)別不同的網(wǎng)站。當(dāng)然,這不是Favicon的全部,根據(jù)瀏覽器的不同,F(xiàn)avicon顯示也有所區(qū)別:在大多數(shù)主流瀏覽器如FireFox和Internet Explorer (5.5及以上版本)中,favicon不僅在收藏夾中顯示,還會(huì)同時(shí)出現(xiàn)在地址欄上,這時(shí)用戶可以拖曳favicon到桌面以建立到網(wǎng)站的快捷方式;除此之外,標(biāo)簽式瀏覽器甚至還有不少擴(kuò)展的功能,如FireFox甚至支持動(dòng)畫格式的favicon等。
問題在於這裡代碼瀏覽器會(huì)自動(dòng)發(fā)起請(qǐng)求網(wǎng)站根目錄的這個(gè)圖標(biāo),干擾測(cè)試,所以接下來的打印結(jié)果大家無視Favicon.ico請(qǐng)求就好。
Koa 應(yīng)用程序是一個(gè)包含一組中間件函數(shù)的對(duì)象,它是按照類似堆棧的方式組織和執(zhí)行的。
當(dāng)一個(gè)中間件調(diào)用 next() 則該函數(shù)暫停并將控制傳遞給定義的下一個(gè)中間件。當(dāng)在下游沒有更多的中間件執(zhí)行后,堆棧將展開并且每個(gè)中間件恢復(fù)執(zhí)行其上游行為。(用一種比較相似的比喻就是中間件相當(dāng)於一次DOM事件,從事件捕捉到事件冒泡的過程)。
const Koa = require("koa"), app = new Koa(); // 一層中間件 app.use((ctx, next) => { console.log("請(qǐng)求資源:" + ctx.url); console.log("一層中間件控制傳遞下去"); next(); console.log("一層中間件控制傳遞回來"); ctx.body = "暗號(hào):Day Day Up"; }); // 二層中間件 app.use((ctx, next) => { console.log("二層中間件控制傳遞下去"); next(); console.log("二層中間件控制傳遞回來"); }); // response app.use(ctx => { console.log("輸出body"); ctx.body = "暗號(hào):Good Good Study"; }); app.listen(3000); console.log("已建立連接,效果請(qǐng)看http://127.0.0.1:3000/"); // 一層中間件控制傳遞下去 // 二層中間件控制傳遞下去 // 輸出body // 二層中間件控制傳遞回來 // 一層中間件控制傳遞回來
(完整代碼可以執(zhí)行koa-demo的 lesson2 查看效果)
從上面結(jié)果可以看出每請(qǐng)求一次資源都會(huì)經(jīng)過所有中間件,并且在執(zhí)行到最尾部中間件時(shí)候會(huì)將控制權(quán)反向傳遞,輸出結(jié)果是頭部的body覆蓋尾部的body。
說實(shí)話沒試過這種方式,有點(diǎn)不習(xí)慣。
Koa Context 將 Nodejs 的 request 和 response 對(duì)象封裝到單個(gè)對(duì)象中,每個(gè)請(qǐng)求都將創(chuàng)建一個(gè) Context,并在中間件中作為接收器引用,或者 ctx 標(biāo)識(shí)符,許多上下文的訪問器和方法直接委托給它們的 ctx.request 或 ctx.response。
我們可以直接打印出來ctx對(duì)象看看有什么。
const Koa = require("koa"), app = new Koa(); // response app.use(async ctx => { console.log("ctx:", ctx); }); app.listen(3000); console.log("已建立連接,效果請(qǐng)看http://127.0.0.1:3000/"); /* ctx: { request: { method: "GET", url: "/", header: { host: "localhost:3000", connection: "keep-alive", "cache-control": "max-age=0", "upgrade-insecure-requests": "1", "user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*!/!*;q=0.8", "accept-encoding": "gzip, deflate, sdch", "accept-language": "zh-CN,zh;q=0.8", cookie: "loginInfo={"username":"abc","password":"MjIyMjIy","rememberMe":1}" } }, response: { status: 404, message: "Not Found", header: {} }, app: { subdomainOffset: 2, proxy: false, env: "development" }, originalUrl: "/", req: "", res: " ", socket: " " }*/
(完整代碼可以執(zhí)行koa-demo的 lesson3 查看效果)
請(qǐng)求(Request)Koa Request 對(duì)象是在 Nodejs 的 vanilla 請(qǐng)求對(duì)象之上的抽象,提供了諸多對(duì) HTTP 服務(wù)器開發(fā)有用的功能。Koa的 Request 對(duì)象包括由 accepts 和 negotiator 提供的有用的內(nèi)容協(xié)商實(shí)體。
request.accepts(types)
request.acceptsEncodings(types)
request.acceptsCharsets(charsets)
request.acceptsLanguages(langs)
如果沒有提供類型,則返回所有可接受的類型;
如果提供多種類型,將返回最佳匹配;
如果沒有找到匹配項(xiàng),則返回一個(gè)false;
因?yàn)橛梅ǘ家粋€(gè)樣,挑選一個(gè)來講解。
request.accepts(types)檢查給定的類型是否可以接受,type 值可能是一個(gè)或多個(gè) mime 類型的字符串或數(shù)組,如果可以就返回最佳匹配類型字符串,否則返回false。
const Koa = require("koa"), app = new Koa(); app .use(async ctx => { switch (ctx.accepts("json", "html", "text")) { case "json": ctx.type = "json"; ctx.body = "匹配類型json
"; break; case "html": ctx.type = "html"; ctx.body = "匹配類型html
"; break; case "text": ctx.type = "text"; ctx.body = "匹配類型text
"; break; default: ctx.throw(406, "json, html, or text only"); } }) .listen(3000); console.log("已建立連接,效果請(qǐng)看http://127.0.0.1:3000/");
(完整代碼可以執(zhí)行koa-demo的 lesson4 查看效果)
實(shí)際開發(fā)中需要更多不同的處理細(xì)節(jié),所以我們可以把內(nèi)容設(shè)置成模板template1.html引用。
匹配類型html
(完整代碼可以執(zhí)行koa-demo的 template1 查看效果)
const Koa = require("koa"), fs = require("fs"), app = new Koa(); app .use(async ctx => { switch (ctx.accepts("json", "html", "text")) { case "html": ctx.type = "html"; ctx.body = fs.createReadStream("./template1.html"); break; default: ctx.throw(406, "json, html, or text only"); } }) .listen(3000); console.log("已建立連接,效果請(qǐng)看http://127.0.0.1:3000/");
(完整代碼可以執(zhí)行koa-demo的 lesson5 查看效果)
路由其實(shí)我們上面的代碼已經(jīng)是原始路由的用法了,我們?cè)黾诱?qǐng)求資源的判斷就可以了,另外新增一個(gè)template2.html模板切換看效果
template2
(完整代碼可以執(zhí)行koa-demo的 template2 查看效果)
然后我們?nèi)サ纛愋团袛嗟却a看效果,直接寫死html即可,不然type默認(rèn)為空,打開頁(yè)面會(huì)觸發(fā)下載的,不信你們?nèi)サ粼O(shè)置類型那行代碼看看。
const Koa = require("koa"), fs = require("fs"), app = new Koa(); app .use(async ctx => { console.log("type: " + ctx.type); switch (ctx.url) { case "/": ctx.type = "html"; ctx.body = fs.createReadStream("./template1.html"); break; case "/template2": ctx.type = "html"; ctx.body = fs.createReadStream("./template2.html"); break; default: ctx.throw(406, "json, html, or text only"); } }) .listen(3000); console.log("已建立連接,效果請(qǐng)看http://127.0.0.1:3000/");
(完整代碼可以執(zhí)行koa-demo的 lesson6 查看效果)
執(zhí)行腳本之后會(huì)默認(rèn)看到template2.html模板內(nèi)容,手動(dòng)換成http://127.0.0.1:3000/template2如果沒設(shè)置type在Chrome會(huì)看到下載彈窗,其他瀏覽器沒試過。
實(shí)際開發(fā)我們不會(huì)這么繁瑣的去區(qū)分路由,上面說過 koa 不在內(nèi)核方法中綁定任何中間件,它僅僅提供了一個(gè)輕量?jī)?yōu)雅的函數(shù)庫(kù),所以我們需要安裝一個(gè)路由中間件。
koa-route3.2.0 ,上次推送已經(jīng)是兩年前了,如果不是放棄維護(hù)就是已經(jīng)很穩(wěn)定了。
yarn add koa-route
如果你需要使用完整特性的路由庫(kù)可以看 koa-router
這里簡(jiǎn)單展示 koa-route 用法。
const Koa = require("koa"), _ = require("koa-route"), fs = require("fs"), app = new Koa(); const route = { index: ctx => { //doSomethings ctx.type = "html"; ctx.body = fs.createReadStream("./template1.html"); }, template2: ctx => { //doSomethings ctx.type = "html"; ctx.body = fs.createReadStream("./template2.html"); }, }; app .use(_.get("/", route.index)) .use(_.get("/template2", route.template2)) .listen(3000); console.log("已建立連接,效果請(qǐng)看http://127.0.0.1:3000/");
(完整代碼可以執(zhí)行koa-demo的 lesson7 查看效果)
響應(yīng)狀態(tài)如果代碼運(yùn)行過程中發(fā)生錯(cuò)誤,我們需要把錯(cuò)誤信息返回給用戶。
ctx.throw([status], [msg], [properties])
等價(jià)于
const err = new Error(msg); err.status = status; err.expose = true; throw err;
注意:這些是用戶級(jí)錯(cuò)誤,并用 err.expose 標(biāo)記,這意味著消息適用于客戶端響應(yīng),這通常不是錯(cuò)誤消息的內(nèi)容,因?yàn)槟幌胄孤┕收显敿?xì)信息。
100 "continue"狀態(tài)碼錯(cuò)誤
101 "switching protocols"
102 "processing"
200 "ok"
201 "created"
202 "accepted"
203 "non-authoritative information"
204 "no content"
205 "reset content"
206 "partial content"
207 "multi-status"
208 "already reported"
226 "im used"
300 "multiple choices"
301 "moved permanently"
302 "found"
303 "see other"
304 "not modified"
305 "use proxy"
307 "temporary redirect"
308 "permanent redirect"
400 "bad request"
401 "unauthorized"
402 "payment required"
403 "forbidden"
404 "not found"
405 "method not allowed"
406 "not acceptable"
407 "proxy authentication required"
408 "request timeout"
409 "conflict"
410 "gone"
411 "length required"
412 "precondition failed"
413 "payload too large"
414 "uri too long"
415 "unsupported media type"
416 "range not satisfiable"
417 "expectation failed"
418 "I"m a teapot"
422 "unprocessable entity"
423 "locked"
424 "failed dependency"
426 "upgrade required"
428 "precondition required"
429 "too many requests"
431 "request header fields too large"
500 "internal server error"
501 "not implemented"
502 "bad gateway"
503 "service unavailable"
504 "gateway timeout"
505 "http version not supported"
506 "variant also negotiates"
507 "insufficient storage"
508 "loop detected"
510 "not extended"
511 "network authentication required"
有兩種寫法,ctx.throw(狀態(tài)碼) 或者 ctx.status = 狀態(tài)碼 ,它們都會(huì)自動(dòng)返回默認(rèn)文字信息,區(qū)別在于兩者設(shè)置返回信息的方式。
注意:默認(rèn)情況下,response.status 設(shè)置為 404 而不是像 node 的 res.statusCode 那樣默認(rèn)為 200。
const Koa = require("koa"), _ = require("koa-route"), app = new Koa(); const router = { "403": ctx => { //doSomethings ctx.throw(403, "403啦!"); }, "404": ctx => { //doSomethings ctx.status = 404; ctx.body = `404啦!
`; }, }; app .use(_.get("/403", router[403])) .use(_.get("/404", router[404])) .listen(3000); console.log("已建立連接,效果請(qǐng)看http://127.0.0.1:3000/");
(完整代碼可以執(zhí)行koa-demo的 lesson8 查看效果)
你們可以分別打開 http://localhost:3000/403 和 http://localhost:3000/404 看輸出結(jié)果。
const Koa = require("koa"), _ = require("koa-route"), app = new Koa(); const router = { index: ctx => { //doSomethings ctx.throw(500, "我是故意的!"); }, }; app .use(_.get("/", router.index)) .on("error", (err, ctx) => { console.error("error", err); }) .listen(3000); console.log("已建立連接,效果請(qǐng)看http://127.0.0.1:3000/"); /* error { InternalServerError: 我是故意的! at Object.throw (C:project estkoa-demo ode_moduleskoalibcontext.js:93:11) at Object.index (C:project estkoa-demolesson9.js:8:18) at C:project estkoa-demo ode_moduleskoa-routeindex.js:39:44 at dispatch (C:project estkoa-demo ode_moduleskoa-composeindex.js:42:32) at C:project estkoa-demo ode_moduleskoa-composeindex.js:34:12 at Application.handleRequest (C:project estkoa-demo ode_moduleskoalibapplication.js:150:12) at Server.handleRequest (C:project estkoa-demo ode_moduleskoalibapplication.js:132:19) at Server.emit (events.js:182:13) at parserOnIncoming (_http_server.js:654:12) at HTTPParser.parserOnHeadersComplete (_http_common.js:109:17) message: "我是故意的!" }*/
(完整代碼可以執(zhí)行koa-demo的 lesson9 查看效果)
錯(cuò)誤捕捉你也能直接使用try...catch()直接處理,但是“error”監(jiān)聽事件就不會(huì)再接收該錯(cuò)誤信息。
const Koa = require("koa"), app = new Koa(); const err = async (ctx, next) => { try { await next(); } catch (err) { ctx.status = 404; ctx.body = `你看看終端有沒打印錯(cuò)誤!
`; } }, index = ctx => { ctx.throw(500); }; app .use(err) .use(index) .on("error", function(err) { console.error("error", err); }) .listen(3000); console.log("已建立連接,效果請(qǐng)看http://127.0.0.1:3000/");
(完整代碼可以執(zhí)行koa-demo的 lesson10 查看效果)
注意,這裡的錯(cuò)誤處理如果使用ctx.throw()方法的話能被“error”事件監(jiān)聽到,不是因?yàn)樵摲椒〞?huì)再拋出新的錯(cuò)誤。
const Koa = require("koa"), app = new Koa(); const err = async (ctx, next) => { try { await next(); } catch (err) { ctx.throw(404, "你看看終端有沒打印錯(cuò)誤!"); } }, index = ctx => { ctx.throw(500); }; app .use(err) .use(index) .on("error", function(err) { console.error("error", err); }) .listen(3000); console.log("已建立連接,效果請(qǐng)看http://127.0.0.1:3000/");
(完整代碼可以執(zhí)行koa-demo的 lesson1 查看效果)1
如果想同時(shí)觸發(fā)錯(cuò)誤監(jiān)聽,KOA也提供了 emit 方法可以實(shí)現(xiàn)。
const Koa = require("koa"), app = new Koa(); const err = async (ctx, next) => { try { await next(); } catch (err) { ctx.status = 404; ctx.body = `你看看終端有沒打印錯(cuò)誤!
`; ctx.app.emit("error", err, ctx); } }, index = ctx => { ctx.throw(500); }; app .use(err) .use(index) .on("error", function(err) { console.error("error", err); }) .listen(3000); console.log("已建立連接,效果請(qǐng)看http://127.0.0.1:3000/"); /* error { InternalServerError: Internal Server Error at Object.throw (C:project estkoa-demo ode_moduleskoalibcontext.js:93:11) at index (C:project estkoa-demolesson12.js:14:18) at dispatch (C:project estkoa-demo ode_moduleskoa-composeindex.js:42:32) at err (C:project estkoa-demolesson12.js:6:19) at dispatch (C:project estkoa-demo ode_moduleskoa-composeindex.js:42:32) at C:project estkoa-demo ode_moduleskoa-composeindex.js:34:12 at Application.handleRequest (C:project estkoa-demo ode_moduleskoalibapplication.js:150:12) at Server.handleRequest (C:project estkoa-demo ode_moduleskoalibapplication.js:132:19) at Server.emit (events.js:182:13) at parserOnIncoming (_http_server.js:654:12) message: "Internal Server Error" } */
(完整代碼可以執(zhí)行koa-demo的 lesson11 查看效果)
靜態(tài)資源聰明的人在上面代碼就能看出一些問題,還記得我們說過忽略 Favicon.ico 的請(qǐng)求麼。我們不僅僅有頁(yè)面的請(qǐng)求,還有其他資源的請(qǐng)求。
我們現(xiàn)在還是通過url判斷返回頁(yè)面,如果是其他靜態(tài)資源如圖片那些又怎么辦?這裡介紹一下依賴庫(kù)koa-static5.0.0,
yarn add koa-static -------------------------- require("koa-static")(root, opts)
通過設(shè)置根目錄和可選項(xiàng)會(huì)配置靜態(tài)資源查找路徑,我們先創(chuàng)建一個(gè)img目錄存放一張圖片,然后在 template3.html 引用,再設(shè)置路徑 require("koa-static")(__dirname + "/img/"),它會(huì)自動(dòng)到指定目錄下查找資源。
沒錯(cuò),我就是首頁(yè)
(完整代碼可以執(zhí)行koa-demo的 template3 查看效果)
const Koa = require("koa"), _ = require("koa-route"), serve = require("koa-static")(__dirname + "/img/"), fs = require("fs"), app = new Koa(); const router = { index: ctx => { //doSomethings ctx.type = "html"; ctx.body = fs.createReadStream("./template3.html"); }, }; app .use(serve) .use(_.get("/", router.index)) .listen(3000); console.log("已建立連接,效果請(qǐng)看http://127.0.0.1:3000/");
(完整代碼可以執(zhí)行koa-demo的 lesson13 查看效果)
如果你還是有些不懂的話修改下路徑,require("koa-static")(__dirname),然后圖片地址換成 "./img/1.gif" 。你就看到還是能找到對(duì)應(yīng)資源。
隨著項(xiàng)目開發(fā)你可能會(huì)安裝越來越多的中間件,所有可以使用koa-compose做中間件管理。這個(gè)很多庫(kù)都有類似的中間件,用於簡(jiǎn)化中間件的使用。
上面我們用來講解 koa 級(jí)聯(lián)的那個(gè)例子可以直接拿來修改使用。
const Koa = require("koa"), compose = require("koa-compose"), app = new Koa(); // 一層中間 const mid1 = (ctx, next) => { console.log("請(qǐng)求資源:" + ctx.url); console.log("一層中間件控制傳遞下去"); next(); console.log("一層中間件控制傳遞回來"); }; // 二層中間 const mid2 = (ctx, next) => { console.log("二層中間件控制傳遞下去"); next(); console.log("二層中間件控制傳遞回來"); }; // response const mid3 = ctx => { console.log("輸出body"); ctx.body = "暗號(hào):Hello World"; }; app.use(compose([mid1, mid2, mid3])).listen(3000); console.log("已建立連接,效果請(qǐng)看http://127.0.0.1:3000/"); // 請(qǐng)求資源:/ // 一層中間件控制傳遞下去 // 二層中間件控制傳遞下去 // 輸出body // 二層中間件控制傳遞回來 // 一層中間件控制傳遞回來
(完整代碼可以執(zhí)行koa-demo的 lesson14 查看效果)
可以看出大概原理就是把引用多個(gè)中間件的使用方式改成將多個(gè)中間件組裝成一個(gè)使用。
我們處理請(qǐng)求的時(shí)候可以用 koa-body 解析請(qǐng)求體。
A full-featured koa body parser middleware. Support multipart, urlencoded and json request bodies. Provides same functionality as Express"s bodyParser - multer. And all that is wrapped only around co-body and formidable.
一個(gè)功能豐富的body解析中間件,支持多部分,urlencoded,json請(qǐng)求體,提供Express里bodyParse一樣的函數(shù)方法
直接安裝依賴
yarn add koa-body
新建一個(gè)提交頁(yè)面
(完整代碼可以執(zhí)行koa-demo的 template4 查看效果)
可以輸出格式看看效果
const Koa = require("koa"), koaBody = require("koa-body"), _ = require("koa-route"), fs = require("fs"), app = new Koa(); const router = { index: ctx => { //doSomethings ctx.type = "html"; ctx.body = fs.createReadStream("./template4.html"); }, }, upload = ctx => { console.log(ctx.request.body); ctx.body = `Request Body: ${JSON.stringify(ctx.request.body)}`; }; app .use(koaBody()) .use(_.get("/", router.index)) .use(_.post("/upload", upload)) .listen(3000); console.log("已建立連接,效果請(qǐng)看http://127.0.0.1:3000/");
(完整代碼可以執(zhí)行koa-demo的 lesson15 查看效果)
提交內(nèi)容之后在頁(yè)面和終端都能看到body內(nèi)容。
Koa (koajs)
Koa examples
Koa 框架教程
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/106737.html
摘要:系列教程,持續(xù)更新系列教程應(yīng)用初見系列教程處理靜態(tài)文件系列教程使用模板引擎系列教程路由控制中間件系列教程綜合搭建登錄注冊(cè)頁(yè)面系列教程實(shí)現(xiàn)登錄注冊(cè)功能這篇教程主要介紹構(gòu)建服務(wù)器,簡(jiǎn)單引用本教程的版本要格外注意版本號(hào)案例簡(jiǎn)單利用搭建服務(wù)器文件夾 koa2系列教程,持續(xù)更新 koa2系列教程:koa2應(yīng)用初見 koa2系列教程:koa2處理靜態(tài)文件 koa2系列教程:koa2使用模板引擎 ...
摘要:系列教程,持續(xù)更新系列教程應(yīng)用初見系列教程處理靜態(tài)文件系列教程使用模板引擎系列教程路由控制中間件系列教程綜合搭建登錄注冊(cè)頁(yè)面系列教程實(shí)現(xiàn)登錄注冊(cè)功能這篇主要介紹處理靜態(tài)文件的中間件用到的版本項(xiàng)目的結(jié)構(gòu)大家可以往文件夾里面添加點(diǎn)東西編輯啟動(dòng) koa2系列教程,持續(xù)更新 koa2系列教程:koa2應(yīng)用初見 koa2系列教程:koa2處理靜態(tài)文件 koa2系列教程:koa2使用模板引擎 k...
摘要:系列教程,持續(xù)更新系列教程應(yīng)用初見系列教程處理靜態(tài)文件系列教程使用模板引擎系列教程路由控制中間件系列教程綜合搭建登錄注冊(cè)頁(yè)面系列教程實(shí)現(xiàn)登錄注冊(cè)功能這篇教大家如何使用模板引擎這里我們使用模板引擎做個(gè)例子,你們自己選擇自己熟練的模板引擎使用的 koa2系列教程,持續(xù)更新 koa2系列教程:koa2應(yīng)用初見 koa2系列教程:koa2處理靜態(tài)文件 koa2系列教程:koa2使用模板引擎 ...
摘要:系列教程,持續(xù)更新系列教程應(yīng)用初見系列教程處理靜態(tài)文件系列教程使用模板引擎系列教程路由控制中間件系列教程綜合搭建登錄注冊(cè)頁(yè)面系列教程實(shí)現(xiàn)登錄注冊(cè)功能本文源碼地址這篇是將前幾天的內(nèi)容做個(gè)綜合,運(yùn)用靜態(tài)文件處理,路由,模板引擎我的版本項(xiàng)目結(jié)構(gòu)是 koa2系列教程,持續(xù)更新 koa2系列教程:koa2應(yīng)用初見 koa2系列教程:koa2處理靜態(tài)文件 koa2系列教程:koa2使用模板引擎 ...
摘要:系列教程,持續(xù)更新系列教程應(yīng)用初見系列教程處理靜態(tài)文件系列教程使用模板引擎系列教程路由控制中間件系列教程綜合搭建登錄注冊(cè)頁(yè)面這篇我們來使用一個(gè)控制一下路由本篇的版本注意版本哦目錄結(jié)構(gòu)編輯子路由子路由裝載所有子路由加載路由中間件啟動(dòng)服務(wù), koa2系列教程,持續(xù)更新 koa2系列教程:koa2應(yīng)用初見 koa2系列教程:koa2處理靜態(tài)文件 koa2系列教程:koa2使用模板引擎 ko...
摘要:系列教程,持續(xù)更新系列教程應(yīng)用初見系列教程處理靜態(tài)文件系列教程使用模板引擎系列教程路由控制中間件系列教程綜合搭建登錄注冊(cè)頁(yè)面系列教程實(shí)現(xiàn)登錄注冊(cè)功能這個(gè)主要結(jié)合前幾天的內(nèi)容,做個(gè)實(shí)際案例的效果版本項(xiàng)目結(jié)構(gòu)前幾天,我們把注冊(cè)和登錄的頁(yè)面實(shí)現(xiàn)了 koa2系列教程,持續(xù)更新 koa2系列教程:koa2應(yīng)用初見 koa2系列教程:koa2處理靜態(tài)文件 koa2系列教程:koa2使用模板引擎 ...
閱讀 3550·2021-09-06 15:13
閱讀 1534·2021-09-02 10:19
閱讀 2481·2019-08-30 15:52
閱讀 929·2019-08-29 15:25
閱讀 1574·2019-08-26 18:36
閱讀 501·2019-08-26 13:23
閱讀 1342·2019-08-26 10:46
閱讀 3508·2019-08-26 10:41