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 实现的简易服务器 (二))

posted @ 2020-10-16 14:29  ayuuuuuu  阅读(124)  评论(0编辑  收藏  举报