koa2 mysql 中間件_Koa2第二篇:中間件

第一篇介紹了生成器目錄設計。xyzcoding:Koa2第一篇:詳解生成器?zhuanlan.zhihu.com0d0d5ed28c8faff90463c18f6eb9a31d.png

接下來學習Koa2的中間件。

Koa2本身只能算一個極簡的HTTP服務器,自身不內置中間件,但是提供中間件內核。中間件是Koa2的核心,因此需要熟練掌握。

中間件是什么?

你可以把一個HTTP請求理解為水流,而各種各樣的中間件類似各種管道,它會對水流進行處理。每個中間件在HTTP請求過程中會改寫請求,響應等數據。

也就是我們常說的洋蔥模型。

我們可以通過一個實例理解上述的過程:

const Koa = require('koa')

const app = new Koa()

// 日志中間件app.use(async (ctx, next) => {

console.log('middleware before await');

const start = new Date()

await next() // 函數控制權轉移 console.log('middleware after await');

const ms = new Date() - start

console.log(`${ctx.method}${ctx.url}-${ms}ms`)

})

app.use(async(ctx, next) => {

console.log('response');

ctx.body = "hello koa2"

})

module.exports = app

終端:

middleware before await

response

middleware after await

中間件寫法

通用函數中間件

// 日志中間件app.use((ctx, next) => {

console.log('middleware before await');

const start = new Date()

return next().then(() => {

console.log('middleware after await');

const ms = new Date() - start

console.log(`${ctx.method}${ctx.url}-${ms}ms`)

})

})

上述寫法不夠簡潔。

生成器函數中間件

const convert = require('koa-convert');

// 日志中間件app.use(function* log(next) {

console.log('middleware before await');

const start = new Date()

yield next

const ms = new Date() - start

console.log(`${this.method}${this.url}-${ms}ms`)

})

這里有個小細節,因為我們這里中間件沒有使用箭頭函數,因此其實這里的this就是我們平時說的上下文對象ctx。這也說明了使用async箭頭函數式中間件時候,為什么Koa2需要顯示提供ctx對象, 就是為了解決此處用this引用會有問題。

async函數中間件

app.use(async ctx => {

ctx.body = 'Hello World';

});

上下文對象

在Koa2中,ctx是一次完整的HTTP請求的上下文,會貫穿這個請求的生命周期。也就是說在整個請求階段都是共享的。

createContext(req, res) {

const context = Object.create(this.context);

// request、response是Koa2內置的對象 // 業務中我們一般通過ctx.request、ctx.response訪問 const request = context.request = Object.create(this.request);

const response = context.response = Object.create(this.response);

// 掛在app自身 context.app = request.app = response.app = this;

// 掛在node原生的內置對象 // req: http://nodejs.cn/api/http.html#http_class_http_incomingmessage // res: http://nodejs.cn/api/http.html#http_class_http_serverresponse context.req = request.req = response.req = req;

context.res = request.res = response.res = res;

request.ctx = response.ctx = context;

request.response = response;

response.request = request;

// 最初的URL context.originalUrl = request.originalUrl = req.url;

// 一個中間件生命周期內公共的存儲空間 context.state = {};

return context;

}

ctx.body

ctx.body主要是Koa2返回數據到客戶端的方法。

// context.js

/**

* Response delegation.

*/

delegate(proto, 'response')

.access('body')

可見ctx.body實際上是對在response.js的body進行賦值操作。

ctx.body的一些特性:可以直接返回一個文本

可以返回一個HTML文本

可以返回JSON

ctx.body = 'hello'

ctx.body = '

h2

'

ctx.body = {

name: 'kobe'

}

get status() {

return this.res.statusCode;

},

/*** Set response status code.** @param {Number} code* @api public*/

set status(code) {

if (this.headerSent) return;

assert(Number.isInteger(code), 'status code must be a number');

assert(code >= 100 && code <= 999, `invalid status code:${code}`);

this._explicitStatus = true;

this.res.statusCode = code;

// 客戶端發送的 HTTP 版本,message.httpVersionMajor 是第一個整數, message.httpVersionMinor 是第二個整數。 // http://nodejs.cn/api/http.html#http_message_httpversion // 設置狀態消息 http://nodejs.cn/api/http.html#http_response_statusmessage if (this.req.httpVersionMajor < 2) this.res.statusMessage = statuses[code];

if (this.body && statuses.empty[code]) this.body = null;

},

/*** Set response body.** @param {String|Buffer|Object|Stream} val* @api public*/

set body(val) {

// this._body是真正的body屬性或者說代理屬性 const original = this._body;

this._body = val;

// no content if (null == val) {

// 204 "no content" if (!statuses.empty[this.status]) this.status = 204;

if (val === null) this._explicitNullBody = true;

this.remove('Content-Type');

this.remove('Content-Length');

this.remove('Transfer-Encoding');

return;

}

// 設置狀態碼 if (!this._explicitStatus) this.status = 200;

// 設置content-type const setType = !this.has('Content-Type');

// string if ('string' === typeof val) {

// text/html or text/plain if (setType) this.type = /^\s*

this.length = Buffer.byteLength(val);

return;

}

// buffer if (Buffer.isBuffer(val)) {

if (setType) this.type = 'bin';

this.length = val.length;

return;

}

// stream if (val instanceof Stream) {

onFinish(this.res, destroy.bind(null, val));

if (original != val) {

val.once('error', err => this.ctx.onerror(err));

// overwriting if (null != original) this.remove('Content-Length');

}

if (setType) this.type = 'bin';

return;

}

// json this.remove('Content-Length');

this.type = 'json';

},

ctx.body的工作原理就是根據其賦值的類型,來對Content-Type頭進行處理,最后根據Content-Type類型值通過res.end,把數據寫入到瀏覽器。

ctx.redirect

瀏覽器重定向一般是向前或者向后重定向。

redirect(url, alt) {

// location if ('back' === url) url = this.ctx.get('Referrer') || alt || '/';

this.set('Location', encodeUrl(url));

// status if (!statuses.redirect[this.status]) this.status = 302;

// html if (this.ctx.accepts('html')) {

url = escape(url);

this.type = 'text/html; charset=utf-8';

this.body = `Redirecting to ${url}.`;

return;

}

// text this.type = 'text/plain; charset=utf-8';

this.body = `Redirecting to${url}.`;

},

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/383016.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383016.shtml
英文地址,請注明出處:http://en.pswp.cn/news/383016.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

mysql命令行如何建庫_MySQL心得2--命令行方式建庫和表

1.創建使用create database或create schema命令可以創建數據庫。create database 庫名create database if not exists 庫名(創建庫并檢驗創建的庫是否存在&#xff0c;不存在則建&#xff0c;存在就不建了)MySQL不允許兩個數據庫使用相同的名字&#xff0c;使用ifnot exists從句…

python 少兒趣味編程下載_PYTHON少兒趣味編程

章認識Python11.1編程語言和Python11.1.1程序設計和編程語言11.1.2Python簡介21.2Python的安裝41.2.1Windows下的Python安裝41.2.2MAC下的Python安裝81.3個程序HelloWorld111.4開發工具IDLE121.4.1IDLE簡介121.4.2用IDLE編寫程序121.4.3IDLE的其他功能161.5小結18第2章變量、數…

rs485數據線接反_終于有人把RS485通訊的正確接線方式講明白了,網友:這下好辦了...

RS485是一個定義平衡數字多點系統中的驅動器和接收器的電氣特性的標準,該標準由電信行業協會和電子工業聯盟定義。使用該標準的數字通信網絡能在遠距離條件下以及電子噪聲大的環境下有效傳輸信號。RS485使得廉價本地網絡以及多支路通信鏈路的配置成為可能。那么RS485通訊的正確…

騎馬與砍殺python代碼_GitHub - yunwei1237/scottish-fold: 一個關于騎馬與砍殺的劇本制作工具...

scottish-fold一個關于騎馬與砍殺的劇本簡單快速的制作工具前言?在很久以前的時候&#xff0c;也就是剛開始玩騎砍的時候就想著能夠制作一個自己的劇本&#xff0c;用于書寫自己想要的故事。當我懷著遠大的夢想去這么做的時候才發現&#xff0c;原來制作劇本沒有自己想象的那么…

java tomcat 監控_java程序監控tomcat實現項目宕機自動重啟并發送郵件提醒

最近由于老項目頻繁掛掉&#xff0c;由于項目經過多批人之手&#xff0c;短時間難以定位問題&#xff0c;所以只好寫一個監控程序。 時間比較緊半天時間&#xff0c;而且水平有限大神勿噴&#xff0c;有好的方法還請賜教。 1、問題描述&#xff1a;分兩種情況1.1、tomcat 徹底掛…

java靜態類和非靜態類的區別_Java中靜態內部類和非靜態內部類到底有什么區別?...

內部類(Inner Class)和靜態內部類(Static Nested Class)的區別&#xff1a;定義在一個類內部的類叫內部類&#xff0c;包含內部類的類稱為外部類。內部類可以聲明public、protected、private等訪問限制&#xff0c;可以聲明 為abstract的供其他內部類或外部類繼承與擴展&#x…

java寫便簽_如何編寫一個便簽程序(用Java語言編寫)

如何編寫一個便簽程序(用Java語言編寫)熱度&#xff1a;336 發布時間&#xff1a;2011-02-18 11:44:16如何編寫一個便簽程序(用Java語言編寫)因為以前沒有好好學習Java&#xff0c;都搞忘了&#xff0c;請大家原諒&#xff0c;也請你們指導一下&#xff0c;怎么編寫這個程序&…

java 生成log4j_Java log4j配置每天生成一個日志文件 - 永恒ぃ☆心 的日志 - 網易博客...

一、配置屬性文件log4j.propertieslog4j.rootLoggerINFO,stdout,Rlog4j.appender.stdoutorg.apache.log4j.ConsoleAppenderlog4j.appender.stdout.layoutorg.apache.log4j.PatternLayout# Pattern to output the callers file name and line number.log4j.appender.stdout.layo…

java 子進程輸出流_具有輸入/輸出流的Java進程

首先&#xff0c;我建議更換這條線路。Process process Runtime.getRuntime ().exec ("/bin/bash");帶著線條ProcessBuilder builder new ProcessBuilder("/bin/bash");builder.redirectErrorStream(true);Process process builder.start();ProcessBuil…

java中if 運算符_[Java]Java基本語法結構(運算符,流程控制語句,if語句)

1:運算符(掌握)(1)算術運算符A:,-,*,/,%,,--B:的用法a:加法b:正號c:字符串連接符C:/和%的區別數據做除法操作的時候&#xff0c;/取得是商&#xff0c;%取得是余數D:和--的用法a:他們的作用是自增或者自減b:使用**單獨使用放在操作數據的前面和后面效果一樣。a或者a效果一樣。*…

java 變量取值范圍_JAVA中的變量及取值范圍

字節是二進制數據的單位。一個字節通常8位長。但是&#xff0c;一些老型號計算機結構使用不同的長度。為了避免混亂&#xff0c;在大多數國際文獻中&#xff0c;使用詞代替byte。變量&#xff1a;變量的數據類型&#xff1b;變量名變量值數據類型基本型數值型(整數)布爾型浮點型…

java object強制類型轉換_scala?object?轉Class?Scala強制類型轉換

asInstanceOf[T]將對象類型強制轉換為T類型。還是由于泛型存在類型擦除的原因,1.asInstanceOf[String]在運行時會拋出ClassCastException異常&#xff0c;而List(1).asInstanceOf[List[String]]將不會。packageresti.webimportorg.springframework.beans.factory.annotation.Au…

java毛玻璃_模糊效果(毛玻璃效果)

模糊效果(毛玻璃效果)效果演示&#xff1a;1. 使用iOS自帶的 UIImageImageEffects 文件文件中有這么幾個方法&#xff1a;- (UIImage *)applyLightEffect;- (UIImage *)applyExtraLightEffect;- (UIImage *)applyDarkEffect;- (UIImage *)applyTintEffectWithColor:(UIColor *)…

java程序崩潰怎么重啟_android 異常崩潰后 重啟app(進程守護方式實現)

【實例簡介】【實例截圖】【核心代碼】package com.sunfusheng.daemon.sample;import android.content.ComponentName;import android.content.Intent;import android.os.Looper;import android.util.Log;import com.blankj.utilcode.util.AppUtils;import com.sunfusheng.daem…

mysql 存儲過程 循環結構 命名_mysql存儲過程----循環結構

循環結構一共分為三種&#xff1a;三種循環結構分別為while、repeat、loop。while循環語法while 表達式(如果表達式為true則執行業務邏輯&#xff0c;否則不執行&#xff0c;與repeat循環相反&#xff0c;repeat循環滿足表達式退出循環&#xff0c;不滿足一直執行) do業務邏輯e…

mysql 組合索引 or_Mysql_組合索引和單列索引

一、目標什么時候使用組合索引&#xff0c;什么時候使用單獨索引組合索引、單獨索引區別組合索引&#xff1a;最左前綴匹配原則二、前期數據準備1. 建表CREATE TABLE user (uidint(11) NOT NULLAUTO_INCREMENT,namevarchar(50) DEFAULT NULL,pwdvarchar(50) DEFAULT NULL,creat…

mysql與mangodb多租戶_MongoDB多租戶(Java):如何使用MongoClient在運行時切換具有不同數據庫憑據的MongoDB數據庫?...

我正面臨一個關于MongoDB多租戶的問題.我有兩個不同的mongoDB數據庫(db1和db2).這兩者都有不同的憑據.db1憑據&#xff1a;userName&#xff1a;admin密碼&#xff1a;passwddb2憑據&#xff1a;userName&#xff1a;admin1密碼&#xff1a;passwd1我需要在運行時從一個數據庫切…

python 庫 全局變量_python局部變量和全局變量global

當你在函數定義內聲明變量的時候&#xff0c;它們與函數外具有相同名稱的其他變量沒有任何關系&#xff0c;即變量名稱對于函數來說是 局部 的。這稱為變量的 作用域 。所有變量的作用域是它們被定義的塊&#xff0c;從它們的名稱被定義的那點開始。使用局部變量例7.3 使用局部…

java 自省_自知 自省 自立 自信 自尊 自治 自強 自制

自知 自省 自立 自信 自尊 自治 自強 自制能知人者有智力&#xff0c;能自知才是真正的智者&#xff1b;能戰勝別人者有力量&#xff0c;能戰勝自己才是真正的強者&#xff1b;能知足者就是富有&#xff0c;能勤奮頑強堅持才是真正的有志者&#xff1b;不失其立足之地的人可以長…

java中json重復數據結構_JAVA把各種數據結構轉換為JSON格式

Java代碼import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import net.sf…