肢解 HTTP 服務器構建

更好閱讀請戳 這裏

1. 最簡單的 http 服務器

// server.js

var http = require("http");

http.createServer(function(request, response) {
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.write("Hello World");
  response.end();
}).listen(8888);

//  node server.js
// 打開http://localhost:8888/,你會看到一個寫着「Hello World」的網頁~

首先咱們來看看服務端模式下如何工做:html

  • 首先須要使用.createServer方法建立一個服務器
  • 而後調用.listen方法監聽端口
  • 以後,每當來了一個客戶端請求,建立服務器時傳入的回調函數就被調用一次。能夠看出,這是一種事件機制

HTTP請求本質上是一個數據流,由請求頭(headers)和請求體(body)組成node

// 請求頭
POST / HTTP/1.1
User-Agent: curl/7.26.0
Host: localhost
Accept: */*
Content-Length: 11
Content-Type: application/x-www-form-urlencoded

// 請求體 
Hello World

HTTP請求在發送給服務器時,能夠認爲是按照從頭至尾的順序一個字節一個字節地以數據流方式發送的。而http模塊建立的HTTP服務器在接收到完整的請求頭後,就會調用回調函數。在回調函數中,可使用request對象訪問請求頭數據並把request對象看成一個只讀數據流來訪問請求體數據git

可修改上述代碼github

// server.js

var http = require("http");

http.createServer(function(request, response) {
  // 讀取 requst 數據流
  console.log('我是請求方法:', request.method)
  console.log('我是請求頭:', request.headers)

  request.on('data', function (chunk) {
    body.push(chunk);
  });
  request.on('end', function () {
    body = Buffer.concat(body);
    console.log('我是請求體呀', body.toString());
  });

  // 處理response
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.write("Hello World");
  response.end();
}).listen(8888);

//  node server.js
// 打開http://localhost:8888/,你會看到一個寫着「Hello World」的網頁~

就這麼簡單,本文 完~web

oh,no
you too young, too simple瀏覽器

2. 肢解代碼

  • var http = require("http")
    • 請求(require)Node.js自帶的 http 模塊,而且把它賦值給 http 變量
  • createServer
    • listen 方法-數值參數指定該 HTTP 服務器監聽的端口號
  • createServer 的參數
    • 基於事件驅動的回調
      • 不管什麼時候咱們的服務器收到一個請求,這個函數就會被調用
  • 請求處理服務器

    onRequest() 函數被觸發的時候,有兩個參數對象
    • request
    • responseapp

      // 發送一個HTTP狀態200和HTTP頭的內容類型
      response.writeHead(200, {"Content-Type": "text/plain"});
      // 添加HTTP主體內容
      response.write("Hello World");
      // 完成響應
      response.end();

3. 模塊封裝

這一步咱們把server.js變成一個真正的Node.js模塊curl

  1. 函數封裝
    將咱們的腳本封裝到一個函數裏面,而後導出該封裝函數函數

    var http = require("http");
    
    function start() {
      function onRequest(request, response) {
        console.log("Request received.");
        response.writeHead(200, {"Content-Type": "text/plain"});
        response.write("Hello World");
        response.end();
      }
    
      http.createServer(onRequest).listen(8888);
      console.log("Server has started.");
    }
    
    exports.start = start;
  2. 模塊引用

    // 如主文件名爲index.js,寫入
    var server = require("./server");
    
    server.start();

    執行 node index.js

4. 路由

全部請求數據都在 request對象中,數據解析,還須要 url, querystring模塊

來,咱們試一試找出瀏覽器的請求路徑~

4.1 獲取路由

var http = require("http");
var url = require('url')

function start(){
  function onRequest(req, res){
    var url = url.parse(req.url)
    // 打印 url 信息
    console.log('server start url', url)
    res.writeHead(200, {"content-type": "text/plain"})
    res.end()
  }
  http.createServer(onRequest).listen(8888)
}

exports.start = start

request.url參數打印:

4.2 有路可尋

引入路由處理

  • 建立route.js,處理路由信息,在index頁面引入該模塊,並做爲 server 中start 函數的參數執行,
  • 解析每個request,獲取其url 路徑進行處理
// server.js
var http = require("http");
var url = require('url')

function start(route){
  function onRequest(req, res){
    var pathname = url.parse(req.url).pathname
    route(pathname)
    res.writeHead(200, {"content-type": "text/plain"})
    res.end()
  }
  http.createServer(onRequest).listen(8888)
}

exports.start = start
// route.js
function route(pathname){
  console.log('route', pathname)
}

exports.route = route

// index.js  引入route
var server = require('./server')
var router = require('./route')
server.start(router.route)

以上代碼咱們實現了有路可尋

爲了不多重的 if..else..,咱們經過對象傳遞一系列請求

  • 首先建立一個 requestManager 模塊,導出多個處理函數
  • 建立 managers 對象:映射不一樣路由的處理方法
  • 將路由與函數的映射關係做爲參數傳遞給 server
  • server 中調用 route 的處理結果

    // requestManager.js
    function start(){
      console.log('route-----start')
      return 'hello start'
    }
    function next(){
      console.log('route-----next')
      return 'hello next'
    }
    exports.start = start
    exports.next = next
    // index.js
    var server = require('./readfile')
    var router = require('./route')
    var requestManager = require('./requestManager')
    
    var managers = []
    managers['/'] = requestManager.start
    managers['/start'] = requestManager.start
    managers['/next'] = requestManager.next
    
    server.start(router.route, managers)
    
    // http://localhost:8888/start, 瀏覽器會輸出「hello start」
    // http://localhost:8888/next 會輸出「hello next」
    // http://localhost:8888/chaoran 會輸出「404」。
  • manager :每個路由提供對應的處理函數

    // server.js
    var http = require("http");
    var url = require('url')
    
    function start(route, manager){
      function onRequest(req, res){
        var pathname = url.parse(req.url).pathname
        console.log('server request for', pathname)
        var content = route(pathname, manager)
        res.writeHead(200, {"content-type": "text/plain"})
        res.write(content)
        res.end()
      }
      http.createServer(onRequest).listen(8888)
    }
    
    exports.start = start
  • 取出managers 中的路由事件進行處理

    // route.js
    function route(pathname, managers){
      console.log('rrr', pathname)
      if(typeof managers[pathname] == 'function'){
        return managers[pathname]()
    
      }else {
        console.log('managers no found')
        return ''
      }
    }
    
    exports.route = route

好啦,用是能用的,就是偶爾會掛 ( ﹁ ﹁ ) ~→

至於node中的並行及如何實現非阻塞,下次咱們結合實例來學習~

參考:

相關文章
相關標籤/搜索