天天看點

使用nodejs和express搭建http web服務簡介使用nodejs搭建HTTP web服務總結

簡介

nodejs作為一個優秀的異步IO架構,其本身就是用來作為http web伺服器使用的,nodejs中的http子產品,提供了很多非常有用的http相關的功能。

雖然nodejs已經帶有http的處理子產品,但是對于現代web應用程式來說,這或許還不太夠,于是我們有了express架構,來對nodejs的内容進行擴充。

今天我們将會介紹一下使用nodejs和express來開發web應用程式的差別。

使用nodejs搭建HTTP web服務

nodejs提供了http子產品,我們可以很友善的使用http子產品來建立一個web服務:

const http = require('http')

const hostname = '127.0.0.1'
const port = 3000

const server = http.createServer((req, res) => {
  res.statusCode = 200
  res.setHeader('Content-Type', 'text/plain')
  res.end('welcome to www.flydean.com\n')
})

server.listen(port, hostname, () => {
  console.log(`please visit http://${hostname}:${port}/`)
})           

上面建立的http服務監聽在3000端口。我們通過使用createServer方法來建立這個http服務。

該方法接受一個callback函數,函數的兩個參數分别是 req (http.IncomingMessage 對象)和一個res(http.ServerResponse 對像)。

在上面的例子中,我們在response中設定了header和body值,并且以一個end方法來結束response。

請求nodejs服務

我們建立好http web服務之後,一般情況下是從web浏覽器端進行通路和調用。但是我們有時候也需要從nodejs後端服務中調用第三方應用的http接口,下面的例子将會展示如何使用nodejs來調用http服務。

先看一個最簡單的get請求:

const http = require('http')
const options = {
  hostname: 'www.flydean.com',
  port: 80,
  path: '/',
  method: 'GET'
}

const req = http.request(options, res => {
  console.log(`status code: ${res.statusCode}`)

  res.on('data', d => {
    console.log(d);
  })
})

req.on('error', error => {
  console.error(error)
})

req.end()
~~~

上面代碼我們使用了http.request來建立一個request,并且傳入了我們自帶的options參數。

我們通過res的回調事件來進行相應的處理。

再看一個簡單的post請求:

~~~js
const http = require('http')

const data = JSON.stringify({
  name: 'flydean'
})

const options = {
  hostname: 'www.flydean.com',
  port: 80,
  path: '/',
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Content-Length': data.length
  }
}

const req = http.request(options, res => {
  console.log(`status code: ${res.statusCode}`)

  res.on('data', d => {
    console.log(d);
  })
})

req.on('error', error => {
  console.error(error)
})

req.write(data)
req.end()           

post和get相似,不同的是options中的method不一樣,同時put可以有多種請求類型,是以我們需要在headers中指定。

同樣的,PUT 和 DELETE 也可以使用同樣的方式來調用。

第三方lib請求post

直接使用nodejs底層的http.request有點複雜,我們需要自己建構options,如果使用第三方庫,比如axios可以讓post請求變得更加簡單:

const axios = require('axios')

axios
  .post('http://www.flydean.com', {
    name: 'flydean'
  })
  .then(res => {
    console.log(`status code: ${res.statusCode}`)
    console.log(res)
  })
  .catch(error => {
    console.error(error)
  })
~~~

上面的例子中,我們直接使用axios的post請求,并将請求結果封存成了promise,然後通過then和catch來進行相應資料的處理。非常的友善。

## 擷取http請求的正文

在上面的例子中,我們通過監聽req的data事件來輸出http請求的正文:

~~~js
  res.on('data', d => {
    console.log(d);
  })
})
~~~

這樣做其實是有問題的,并不一定能夠獲得完整的http請求的正文。

因為res的on data事件是在伺服器獲得http請求頭的時候觸發的,這個時候請求的正文可能還沒有傳輸完成,換句話說,請求回調中的request是一個流對象。

我們需要這樣處理:

~~~js
const server = http.createServer((req, res) => {
  let data = []
  req.on('data', chunk => {
    data.push(chunk)
  })
  req.on('end', () => {
    console.log(JSON.parse(data));
  })
})
~~~

當每次觸發data事件的時候,我們将接受到的值push到一個數組裡面,等所有的值都接收完畢,觸發end事件的時候,再統一進行輸出。

這樣處理顯然有點麻煩。

我們介紹一個在express架構中的簡單方法,使用 body-parser 子產品:

~~~js
const bodyParser = require('body-parser')

app.use(
  bodyParser.urlencoded({
    extended: true
  })
)

app.use(bodyParser.json())

app.post('/', (req, res) => {
  console.log(req.body)
})
~~~

上面的例子中,body-parser對req進行了封裝,我們隻用關注與最後的結果即可。

# Express和使用express搭建http web服務

express是什麼呢?

express是基于 Node.js 平台,快速、開放、極簡的 web 開發架構。它提供一系列強大的特性,幫助你建立各種 Web 和移動裝置應用。

豐富的 HTTP 快捷方法和任意排列組合的 Connect 中間件,讓你建立健壯、友好的 API 變得既快速又簡單。

Express 不對 Node.js 已有的特性進行二次抽象,我們隻是在它之上擴充了 Web 應用所需的基本功能。

## express helloworld

我們看一下怎麼使用Express來搭建一個helloworld:

~~~js
var express = require('express');
var app = express();
app.get('/', function (req, res) {
  res.send('Hello World!');
});
var server = app.listen(3000, function () {
  var host = server.address().address;
  var port = server.address().port;
  console.log('Example app listening at http://%s:%s', host, port);
});

~~~

簡單的使用app.listen即可搭建好一個http web服務。

## express路由

有了web服務,我們需要對不同的請求路徑和請求方式進行不同的處理,這時候就需要使用到了express路由功能:

~~~js
// 對網站首頁的通路傳回 "Hello World!" 字樣
app.get('/', function (req, res) {
  res.send('Hello World!');});
// 網站首頁接受 POST 請求
app.post('/', function (req, res) {
  res.send('Got a POST request');});
// /user 節點接受 PUT 請求
app.put('/user', function (req, res) {
  res.send('Got a PUT request at /user');});
// /user 節點接受 DELETE 請求
app.delete('/user', function (req, res) {
  res.send('Got a DELETE request at /user');});
~~~

更進階一點的,我們還可以在請求路徑中做路由比對:

~~~js
// 比對 acd 和 abcd
app.get('/ab?cd', function(req, res) {
  res.send('ab?cd');});
// 比對 abcd、abbcd、abbbcd等
app.get('/ab+cd', function(req, res) {
  res.send('ab+cd');
});
// 比對 abcd、abxcd、abRABDOMcd、ab123cd等
app.get('/ab*cd', function(req, res) {
  res.send('ab*cd');
});
// 比對 /abe 和 /abcde
app.get('/ab(cd)?e', function(req, res) {
 res.send('ab(cd)?e');});

// 比對任何路徑中含有 a 的路徑:
app.get(/a/, function(req, res) {
  res.send('/a/');
});

// 比對 butterfly、dragonfly,不比對 butterflyman、dragonfly man等
app.get(/.*fly$/, function(req, res) {
  res.send('/.*fly$/');
});
           

Express 路由句柄中間件

有時候,一個請求可能有多個處理器,express提供了路由句柄(中間件)的功能,我們可自由組合處理程式。

注意,在路由句柄中,我們需要調用next方法,來觸發下一個路由方法。
var cb0 = function (req, res, next) {
  console.log('CB0');
  next();}
var cb1 = function (req, res, next) {
  console.log('CB1');
  next();}
app.get('/example/d', [cb0, cb1], function (req, res, next) {
  console.log('response will be sent by the next function ...');
  next();
}, function (req, res) {
  res.send('Hello from D!');
});           

上面的請求會經過cb0,cb1和自定義的兩個function,最終結束。

Express 響應方法

express提供了很多響應方法API,可以友善我們的代碼編寫:

方法 描述
res.download() 提示下載下傳檔案。
res.end() 終結響應處理流程。
res.json() 發送一個 JSON 格式的響應。
res.jsonp() 發送一個支援 JSONP 的 JSON 格式的響應。
res.redirect() 重定向請求。
res.render() 渲染視圖模闆。
res.send() 發送各種類型的響應。
res.sendFile 以八位位元組流的形式發送檔案。
res.sendStatus() 設定響應狀态代碼,并将其以字元串形式作為響應體的一部分發送。

Express 的靜态資源

通常來說,靜态資源是不需要服務端進行處理的,在express中,可以使用express.static來指定靜态資源的路徑:

app.use(express.static('public'));
現在,public 目錄下面的檔案就可以通路了。
http://localhost:3000/images/kitten.jpg
http://localhost:3000/css/style.css
http://localhost:3000/js/app.js
http://localhost:3000/images/bg.png
http://localhost:3000/hello.html
//多個靜态資源目錄
app.use(express.static('public'));
app.use(express.static('files'));
//靜态字首
app.use('/static', express.static('public'));
http://localhost:3000/static/images/kitten.jpg
http://localhost:3000/static/css/style.css           

Express 使用模闆引擎

web應用當然需要html檔案,express中可以使用多種模闆語言,讓編寫html頁面更加容易。如果想要使用模闆引擎。我們可以使用下面的步驟:

  1. views, 放模闆檔案的目錄,比如: app.set('views', './views')
  2. view engine, 模闆引擎,比如: app.set('view engine', 'jade')
  3. 在 views 目錄下生成名為 index.jade 的 Jade 模闆檔案,内容如下:
html
  head
    title!= title
  body
    h1!= message           
  1. 在nodejs服務端配置route規則
//配置route 規則
app.get('/', function (req, res) {
  res.render('index', { title: 'Hey', message: 'Hello there!'});
});           

總結

nodejs和express是非常友善的http web服務架構,希望大家能夠喜歡。

本文作者:flydean程式那些事

本文連結:

http://www.flydean.com/nodejs-http-express/

本文來源:flydean的部落格

歡迎關注我的公衆号:「程式那些事」最通俗的解讀,最深刻的幹貨,最簡潔的教程,衆多你不知道的小技巧等你來發現!

繼續閱讀