1. 程式人生 > >淺談express 中介軟體機制及實現原理

淺談express 中介軟體機制及實現原理

中介軟體機制可以讓我們在一個給定的流程中新增一個處理步驟,從而對這個流程的輸入或者輸出產生影響,或者產生一些中作用、狀態,或者攔截這個流程。中介軟體機制和tomcat的過濾器類似,這兩者都屬於責任鏈模式的具體實現。

express 中介軟體使用案例

1

2

3

4

5

6

7

8

9

10

let express = require('express')

let app = express()

//解析request 的body

app.use(bodyParser.json())

//解析 cookie

app.use(cookieParser())

//攔截

app.get('/hello', function (req, res) {

res.send('Hello World!');

});

模擬中介軟體機制並且模擬實現解析request的中介軟體

首先模擬一個request

1

2

3

4

5

request = { //模擬的request

requestLine: 'POST /iven_ HTTP/1.1',

headers: 'Host:www.baidu.com\r\nCookie:BAIDUID=E063E9B2690116090FE24E01ACDDF4AD:FG=1;BD_HOME=0'

,

requestBody: 'key1=value1&key2=value2&key3=value3',

}

一個http請求分為請求行、請求頭、和請求體,這三者之間通過\r\n\r\n即一個空行來分割,這裡假設已經將這三者分開,requestLine(請求行)中有方法型別,請求url,http版本號,這三者通過空格來區分,headers(請求頭)中的各部分通過\r\n來分割,requestBody(請求體)中通過 & 來區分引數

模擬中介軟體機制

約定中介軟體一定是一個函式並且接受 request, response, next三個引數

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

function App() {

if (!(this instanceof App))

return new App();

this.init();

}

App.prototype = {

constructor: App,

init: function() {

this.request = { //模擬的request

requestLine: 'POST /iven_ HTTP/1.1',

headers: 'Host:www.baidu.com\r\nCookie:BAIDUID=E063E9B2690116090FE24E01ACDDF4AD:FG=1;BD_HOME=0',

requestBody: 'key1=value1&key2=value2&key3=value3',

};

this.response = {}; //模擬的response

this.chain = []; //存放中介軟體的一個數組

this.index = 0; //當前執行的中介軟體在chain中的位置

},

use: function(handle) { //這裡預設 handle 是函式,並且這裡不做判斷

this.chain.push(handle);

},

next: function() { //當呼叫next時執行index所指向的中介軟體

if (this.index >= this.chain.length)

return;

let middleware = this.chain[this.index];

this.index++;

middleware(this.request, this.response, this.next.bind(this));

},

}

對 request 處理的中介軟體

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

function lineParser(req, res, next) {

let items = req.requestLine.split(' ');

req.methond = items[0];

req.url = items[1];

req.version = items[2];

next(); //執行下一個中介軟體

}

function headersParser(req, res, next) {

let items = req.headers.split('\r\n');

let header = {}

for(let i in items) {

let item = items[i].split(':');

let key = item[0];

let value = item[1];

header[key] = value;

}

req.header = header;

next(); //執行下一個中介軟體

}

function bodyParser(req, res, next) {

let bodyStr = req.requestBody;

let body = {};

let items = bodyStr.split('&');

for(let i in items) {

let item = items[i].split('=');

let key = item[0];

let value = item[1];

body[key] = value;

}

req.body = body;

next(); //執行下一個中介軟體

}

function middleware3(req, res, next) {

console.log('url: '+req.url);

console.log('methond: '+req.methond);

console.log('version: '+req.version);

console.log(req.body);

console.log(req.header);

next(); //執行下一個中介軟體

}

測試程式碼

?

1

2

3

4

5

6

let app = App();

app.use(lineParser);

app.use(headersParser);

app.use(bodyParser);

app.use(middleware3);

app.next();

整體程式碼

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

function App() {

if (!(this instanceof App))

return new App();

this.init();

}

App.prototype = {

constructor: App,

init: function() {

this.request = { //模擬的request

requestLine: 'POST /iven_ HTTP/1.1',

headers: 'Host:www.baidu.com\r\nCookie:BAIDUID=E063E9B2690116090FE24E01ACDDF4AD:FG=1;BD_HOME=0',

requestBody: 'key1=value1&key2=value2&key3=value3',

};

this.response = {}; //模擬的response

this.chain = []; //存放中介軟體的一個數組

this.index = 0; //當前執行的中介軟體在chain中的位置

},

use: function(handle) { //這裡預設 handle 是函式,並且這裡不做判斷

this.chain.push(handle);

},

next: function() { //當呼叫next時執行index所指向的中介軟體

if (this.index >= this.chain.length)

return;

let middleware = this.chain[this.index];

this.index++;

middleware(this.request, this.response, this.next.bind(this));

},

}

function lineParser(req, res, next) {

let items = req.requestLine.split(' ');

req.methond = items[0];

req.url = items[1];

req.version = items[2];

next(); //執行下一個中介軟體

}

function headersParser(req, res, next) {

let items = req.headers.split('\r\n');

let header = {}

for(let i in items) {

let item = items[i].split(':');

let key = item[0];

let value = item[1];

header[key] = value;

}

req.header = header;

next(); //執行下一個中介軟體

}

function bodyParser(req, res, next) {

let bodyStr = req.requestBody;

let body = {};

let items = bodyStr.split('&');

for(let i in items) {

let item = items[i].split('=');

let key = item[0];

let value = item[1];

body[key] = value;

}

req.body = body;

next(); //執行下一個中介軟體

}

function middleware3(req, res, next) {

console.log('url: '+req.url);

console.log('methond: '+req.methond);

console.log('version: '+req.version);

console.log(req.body);

console.log(req.header);

next(); //執行下一個中介軟體

}

let app = App();

app.use(lineParser);

app.use(headersParser);

app.use(bodyParser);

app.use(middleware3);

app.next();

執行結果

將以上整體程式碼執行後將列印以下資訊

?

1

2

3

4

5

url: /iven_

methond: POST

version: HTTP/1.1

{key1: "value1", key2: "value2", key3: "value3"}

{Host: "www.baidu.com", Cookie: "BAIDUID=E063E9B2690116090FE24E01ACDDF4AD"}