• Node.js 实现的简易服务器 (一) (非阻塞处理存在问题)


    index.js

    const server = require('./server');
    const router = require('./router');
    
    server.start(router.route);
    

    server.js

    const http = require('http');  // Node.js 内置的 http 模块
    const url = require('url');  // Node.js 内置的 url 模块
    
    
    function start(route, port=8080) {
        /**
         * 请求事件发生时调用的回调函数 (Node.js 是执行单线程异步非阻塞事件驱动的)
         */
        function requestListener(req, resp) {
            let pathname = url.parse(req.url).pathname;
            console.log(`Request for ${pathname} received.`);
    
            let content = route(pathname);
    
            resp.writeHead(200, { 'Content-Type': 'text/html' });  // 响应头
            resp.write(content);  // 响应主体
            resp.end();  // 完成响应
        }
    
    
        /**
         * 创建一个基础的 HTTP 服务器
         * 
         * 请求 http 模块提供的函数 createServer 创建一个服务器对象, 并调用该对象的 listen 方法监听 8080 端口
         * 
         * See Also: 
         * createServer 函数的源码解析: https://blog.csdn.net/THEANARKH/article/details/88385964
         * Node.js 是事件驱动: https://segmentfault.com/a/1190000014926921
         */
        http.createServer(requestListener).listen(port);
    
        console.log(`Server has started on ${port}`);
    }
    
    
    module.exports = {
        start
    }
    

    router.js

    const requestHandlers = require('./requestHandlers');
    
    // 路由映射/注册
    const handler = {
        '/': requestHandlers.start,
        '/start': requestHandlers.start,
        '/upload': requestHandlers.upload
    };
    
    // 路由处理
    function route(pathname) {
        console.log(`About to route a request for ${pathname}`);
        let handle = handler[pathname];
        if (typeof handle === 'function') {
            let result = handle();
            console.log(`${handle.name} was called`);
            return result;
        } else {
            console.log(`No request handle found for ${pathname}`);
            return '404 Not Found';
        }
    }
    
    
    module.exports = {
        route
    }
    

    requestHandlers.js

    function start() {
        const exec = require('child_process').exec;
        let result = 'empty';
    
        exec(`echo 'hello'`, function (error, stdout, stderr) {
            result = stdout;
            console.log(result);
        });
    
        return result;
    }
    
    function upload() {
        return 'upload';
    }
    
    
    module.exports = {
        start,
        upload
    }
    

    特点

    • 请求处理程序进行阻塞操作时, 会阻塞其他请求的处理
      (原因: 主(执行)线程被阻塞代码阻塞后, 其余所有请求必须等待该阻塞代码处理完毕之后才能执行)

    缺点

    • 请求处理程序进行非阻塞操作时, 无法正确返回响应内容
      (原因: 请求处理程序是以阻塞方式运行的, 非阻塞代码的回调函数还未执行获取到响应内容, 请求已经返回了, 故 start() 请求处理函数始终返回 empty)

    总结

    该服务器分为三层:

    • server - 用于启动服务器, 接收请求与返回响应
    • router - 用于路由注册和路由处理
    • requestHandlers - 用于编写业务逻辑, 实现各个请求处理函数

    各层之间的通信顺序为: req -> server -> router -> requestHandlers -> router -> server -> resp, 其中 server 返回的 resp 依赖于 requestHandlers 请求处理程序的返回内容 (采用将内容传递给服务器的方式), 这就导致了如果请求处理程序中存在非阻塞代码获取返回结果时 (如上述代码中的 child_process.exec 异步非阻塞执行命令行命令) , 响应内容就会与我们期望不符 (解决方案见->Node.js 实现的简易服务器 (二))

  • 相关阅读:
    opengl像素格式管理
    opengl的体系结构
    符号文件——Windows 应用程序调试必备
    [Study Note] Patterns in Practice 20100404
    “在我的机器上可以运行”症状自查(Windows编程)
    [Study Note] Patterns in Practice 20100402
    [Study Note] Patterns in Practice 20100406
    [Study Note] Design and Testability 20100410
    [Study Note] Patterns in Practice 20100403
    [Study Note] Design and Testability 20100411
  • 原文地址:https://www.cnblogs.com/ayuuuuuu/p/13826315.html
Copyright © 2020-2023  润新知