Node.js超詳細零基礎教程(1)—處理GET、POST請求

基於nodejs的服務端開發已經有express、koa2等成熟框架。熟練使用這些框架並不難,但背後的原理是怎樣的,不少同窗並無作到知其因此然。node

本nodejs系列教程先拋開框架,原生搭建nodejs後服務,在掌握原理後,再去學習express、koa2框架。web

經過開發一個ToDoList小項目,掌握經常使用的nodejs開發。大體分爲如下幾個階段:ajax

【第一階段】不借助框架開發nodejs後端服務,包括數據的接收、處理、返回,路由,MySQL、Redis對接,登陸驗證,簡單的安全防範等(分較多期進行講解)。express

【第二階段】使用express重構項目npm

【第三階段】使用koa2重構項目json

第一階段將花費大量篇幅講解,當咱們深刻了解原理後再去學習express、koa2就會理解得更加透徹。windows

重要的事情說三遍:懂原理!懂原理!懂原理!後端

1 初始化項目

1.1 建立項目目錄

找個喜歡的地方,新建並初始化項目,執行如下命令:api

mkdir node-server
cd node-server
npm init -y
複製代碼

1.2 編寫服務腳本

在項目根目錄下建立bin/www.js。瀏覽器

+  |- /bin
+     |- www.js
   |- package.json
複製代碼

啓動web服務須要使用nodejs的http模塊,打開 bin/www.js 編寫代碼:

const http = require('http')

// 設置服務器端口
const PORT = 8000

// 建立服務器
const server = http.createServer((req, res) => {
   // 返回的內容
   res.end('hello nodejs')
});

// 設置服務器端口
server.listen(PORT)

console.log('node-server started at port http://localhost:' + PORT)
複製代碼

配置入口文件,修改package.json

"name": "node-server",
      "version": "1.0.0",
      "description": "",
M     "main": "./bin/www.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
+       "dev": "node ./bin/www.js"
      },
複製代碼

【關於main字段】

官方說明的原文是這樣的:

The main field is a module ID that is the primary entry point to your program. That is, if your package is named foo, and a user installs it, and then does require("foo"), then your main module’s exports object will be returned.

This should be a module ID relative to the root of your package folder.

For most modules, it makes the most sense to have a main script and often not much else.

main字段是一個模塊ID,是指向你程序的主入口。也就是說,若是你的package名叫foo,那麼一個用戶安裝了你這個package,而且執行require("foo"),你的main模塊的exports對象將會被返回。

這個模塊ID應該相對於你的package根目錄。

對於大多數的模塊來講,設置main仍是很是有意義的,除此以外也沒有其餘鳥用了。

【關於script字段】

官方說明的原文是這樣的:

The 「scripts」 property is a dictionary containing script commands that are run at various times in the lifecycle of your package. The key is the lifecycle event, and the value is the command to run at that point.

scripts是一個包含了腳本命令的dictionary,能夠在package不一樣的生命週期中被執行。key是生命週期事件,value是要運行的命令。

英語比較好的同窗能夠參看官方原文:docs.npmjs.com/files/packa…

回到咱們的項目來,項目的主入口文件是./bin/www.js。

如今,在項目根目錄下執行npm run dev,就等同於執行node ./bin/www.js。 執行後,在控制檯能夠看到輸出,說明服務已經正常啓動:

node-server started at port http://localhost:8000
複製代碼

瀏覽器打開http://localhost:8000,出現「hello nodejs」。

2 設置服務自動熱啓動

每次修改代碼都要重啓服務器才能生效很麻煩,使用nodemon來實現自動監測代碼變化並重啓。

另外,安裝cross-env能夠方便的跨平臺設置環境變量(例如,windows用%ENV_VAR%,其餘系統可能使用$ENV_VAR,不統一)

npm install nodemon cross-env --save-dev
複製代碼

修改package.json:

"scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
M       "dev": "cross-env NODE_ENV=dev nodemon ./bin/www.js"
    },
複製代碼

再次執行npm run dev的時候,若是代碼有改動,web服務會自動重啓,這樣就方便多啦。

3 處理GET請求

瀏覽器訪問http://localhost:8000?id=1&name=demo,至關於咱們發送了一個GET請求,而且傳遞了兩個變量和值。

接下來咱們實現:接收GET請求,並把GET請求傳遞的數據再返回給瀏覽器。

修改bin/www.js:

const http = require('http')
+   const querystring = require('querystring')
   
+   // 設置服務器端口
    const PORT = 8000

    // 建立服務器
    const server = http.createServer((req, res) => {
+       // 獲取請求的url
+       const url = req.url
+       // 獲取請求的method
+       const method = req.method
+       // 解析URL,把url中?後面的參數轉換爲對象
+       const query = querystring.parse(url.split('?')[1])
       
+       // 設置返回數據的Content-type爲JSON
+       res.setHeader('Content-type', 'application/json')
    
+       if (method === 'GET') {
+           // 返回的數據
+           let resData = {
+               error: 0,
+               message: 'GET返回成功',
+               data: {
+                   query: query
+               }
+           }
+           // 將對象轉換爲json字符串
+           res.end(JSON.stringify(resData));
+           return
+       }
+       // 若是沒有匹配,則返回404頁面
+       res.writeHead(200, {'content-type': 'text/plain'});
+       res.write('404 Not Found\n')
+       res.end()

-       // 返回的內容            <--刪除
-       res.end('hello nodejs')  <--刪除
    });

    // 設置服務器端口
    server.listen(PORT)

    console.log('node-server started at port http://localhost:' + PORT)
複製代碼

瀏覽器訪問http://localhost:8000?id=1&name=demo,能夠看到返回的數據了。

【原理講解】

接收GET請求數據仍是很簡單的,關鍵點就是使用const query = querystring.parse(url.split('?')[1])把url中?後面的參數直接解析好了。

4 下載安裝postman

由於POST請求不能像GET請求同樣經過瀏覽器的URL直接發起請求,因此在講解處理POST請求以前,咱們先postman這個工具軟件。

postman是一款能夠模擬各類請求的工具,方便咱們進行POST調試,不然咱們還要去作一個靜態頁。經過ajax等方式去請求。

官方建議下載桌面端APP,www.getpostman.com/downloads/

5 處理POST請求

啓動postman,咱們把請求方式改成POST,輸入請求地址http://localhost:8000/

點擊下方的Body標籤,能夠看到發起POST請求的content-type有好多種。

這裏咱們以application/jsonform-data爲例,分別講解如何接收POST數據。

5.1 接收application/json數據

首先咱們要知道的是,POST數據是以二進制流的方式進行傳輸,因此要不斷的接收數據,直到數據流結束。

修改bin/www.js:

...(略)
    const server = http.createServer((req, res) => {
        const url = req.url
        const method = req.method
        const query = querystring.parse(url.split('?')[1])
+       const contentType = req.headers['content-type']
       
        // 設置返回數據的Content-type爲JSON
        res.setHeader('Content-type', 'application/json')

        if (method === 'GET') {...}

+       if (method === 'POST') {
+           if (contentType === 'application/json') {
+               let postData = '';
+               req.on('data', chunk => {
+                   // chunk是原始二進制數據,須要轉化成字符串
+                   postData += chunk.toString()
+               })
+               req.on('end', () => {
+                   res.end(postData)
+               })
+               return
+           }
+       }
       ...(略)
複製代碼

【原理講解】

  1. 經過req.headers['content-type']獲取請求的數據格式,若是是applicatin/json則進入下面的邏輯。
  2. 建立postData變量,用來存儲post數據。
  3. 在接收數據流的時候,會不斷觸發request的data事件,postData持續累積數據。
  4. 當數據流接收完畢,會觸發request的end事件,返回給客戶端最終結果。

按照下圖設置postman:

點擊Send後,可在下方看到返回的JSON數據。

切換到Header標籤,能夠看到返回數據的content-type爲application/json。

5.2 接收form-data數據

在項目開發時,特別是jQuery項目,咱們常用formData提交數據,例如:

var formData = new FormData();
formData.append('username', 'admin')
formData.append('password', 123456)
$.ajax({
    type: 'POST',
    url: 'api/',
    data: formData, 
    dataType: 'json',
    processData: false,
    contentType: false,
    success: function(obj) {
        console.log(obj)
    }
})
複製代碼

若是用5.1章節的方式,接收到的數據是這樣的:

------WebKitFormBoundaryQrEkLmfuhHhIu5vy 
Content-Disposition: form-data; name="username"

admin
------WebKitFormBoundaryQrEkLmfuhHhIu5vy       
Content-Disposition: form-data; name="password"

123456
------WebKitFormBoundaryQrEkLmfuhHhIu5vy--
複製代碼

須要咱們自行解析,比較麻煩。這裏推薦安裝multiparty插件。

npm install multiparty --save
複製代碼

修改bin/www.js:

const http = require('http')
    const querystring = require('querystring')
+   const multiparty = require('multiparty')
    
    const PORT = 8000

    const server = http.createServer((req, res) => {
        ...(略)
        if (method === 'GET') {...}

        if (method === 'POST') { 
            if (contentType === 'application/json') { ... }
+           else if (contentType.indexOf('multipart/form-data') !== -1) {
+               let form = new multiparty.Form()
+               form.parse(req, function(err, fields, files) {
+                   res.end(JSON.stringify({fields: fields, files: files}));
+               });
+               return
            }
        }
        ...(略)
複製代碼

【原理講解】

1.爲什麼使用contentType.indexOf('multipart/form-data') !== -1來判斷是否是multipart/form-data類型?

由於經過form-data提交的數據content-type的值是相似

multipart/form-data;boundary=----WebKitFormBoundaryMxVY9JCuXKMvmRuL

的形式,所以使用indexOf()。

2.let form = new multiparty.Form()可方便的解析form-data數據。fields裏能夠獲取提交的數據變量及值,files裏獲取提交的文件數據。

3.使用JSON.stringify()將對象轉化爲JSON字符串返回給客戶端。

點擊Send以後,能夠看到數據已經正常返回了。

以上就是本期分享,對GET和POST請求的處理方式進行了講解。這是基於Node.js開發後端服務最最基本的功能了。

下期咱們將講解如何更加科學合理的設置目錄結構以及拆分代碼文件,更側重於架構方面,敬請期待~

歡迎關注個人我的微信公衆號,隨時獲取最新文章^_^

相關文章
相關標籤/搜索