zoukankan      html  css  js  c++  java
  • 肢解 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”的网页~
    

    首先我们来看看服务端模式下如何工作:

    • 首先需要使用.createServer方法创建一个服务器
    • 然后调用.listen方法监听端口
    • 之后,每当来了一个客户端请求,创建服务器时传入的回调函数就被调用一次。可以看出,这是一种事件机制

    HTTP请求本质上是一个数据流,由请求头(headers)和请求体(body)组成

    // 请求头
    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对象当作一个只读数据流来访问请求体数据

    可修改上述代码

    // 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”的网页~
    

    就这么简单,本文 完~

    oh,no
    you too young, too simple

    2. 肢解代码

    • var http = require("http")

      • 请求(require)Node.js自带的 http 模块,并且把它赋值给 http 变量
    • createServer

      • listen 方法-数值参数指定该 HTTP 服务器监听的端口号
    • createServer 的参数

      • 基于事件驱动的回调
        • 无论何时我们的服务器收到一个请求,这个函数就会被调用
    • 请求处理

      onRequest() 函数被触发的时候,有两个参数对象

      • request
      • response
        // 发送一个HTTP状态200和HTTP头的内容类型
        response.writeHead(200, {"Content-Type": "text/plain"});
        // 添加HTTP主体内容
        response.write("Hello World");
        // 完成响应
        response.end();
        

    3. 模块封装

    这一步我们把server.js变成一个真正的Node.js模块

    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中的并行及如何实现非阻塞,下次我们结合实例来学习~

    参考:

  • 相关阅读:
    Linux常用软件 分类: arm-linux-Ubuntu 2013-07-22 16:28 301人阅读 评论(0) 收藏
    Linux系统信息查看命令大全 分类: arm-linux-Ubuntu 2013-07-22 16:28 302人阅读 评论(0) 收藏
    解决VC6下调不出MSDN的问题! 分类: VC++ 2013-07-22 16:28 297人阅读 评论(0) 收藏
    Shell编程基础 分类: arm-linux-Ubuntu 2013-07-22 16:28 189人阅读 评论(0) 收藏
    linux内核体系结构 分类: arm-linux-Ubuntu 2013-07-22 16:28 359人阅读 评论(0) 收藏
    Linux分区和挂载(mount命令的学习) 分类: arm-linux-Ubuntu 2013-07-22 16:28 265人阅读 评论(0) 收藏
    重新编译Linux内核必要性及其准备工作 分类: arm-linux-Ubuntu 2013-07-22 16:28 288人阅读 评论(0) 收藏
    ubuntu11.04启动 及虚拟文件系统 分类: arm-linux-Ubuntu 2013-07-22 16:28 369人阅读 评论(0) 收藏
    VxWorks 任务 分类: vxWorks 2013-07-22 16:28 646人阅读 评论(0) 收藏
    vxWorks 命令 分类: vxWorks 2013-07-22 16:28 544人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/chaoran/p/9394987.html
Copyright © 2011-2022 走看看