• node 静态伺服(搭建服务)


    基本功能

    不急着写下第一行代码,而是先梳理一下就基本功能而言有哪些步骤。

    1. 在本地根据指定端口启动一个http server,等待着来自客户端的请求
    2. 当请求抵达时,根据请求的url,以设置的静态文件目录为base,映射得到文件位置
    3. 检查文件是否存在
    4. 如果文件不存在,返回404状态码,发送not found页面到客户端
    5. 如果文件存在:
      • 打开文件待读取
      • 设置response header
      • 发送文件到客户端
    6. 等待来自客户端的下一个请求

    实现基本功能

    代码结构

    创建一个nodejs-static-webserver目录,在目录内运行npm init初始化一个package.json文件。

    mkdir nodejs-static-webserver && cd "$_"
    // initialize package.json
    npm init

    接着创建如下文件目录:

    -- config
    ---- default.json
    -- static-server.js
    -- app.js

    default.json

    {
        "port": 9527,
        "root": "/Users/sheila1227/Public",
        "indexPage": "index.html"
    }

    default.js存放一些默认配置,比如端口号、静态文件目录(root)、默认页(indexPage)等。当这样的一个请求http://localhost:9527/myfiles/抵达时. 如果根据root映射后得到的目录内有index.html,根据我们的默认配置,就会给客户端发回index.html的内容。

    static-server.js

    const http = require('http');
    const path = require('path');
    const config = require('./config/default');
    
    class StaticServer {
        constructor() {
            this.port = config.port;
            this.root = config.root;
            this.indexPage = config.indexPage;
        }
    
        start() {
            http.createServer((req, res) => {
                const pathName = path.join(this.root, path.normalize(req.url));
                res.writeHead(200);
                res.end(`Requeste path: ${pathName}`);
            }).listen(this.port, err => {
                if (err) {
                    console.error(err);
                    console.info('Failed to start server');
                } else {
                    console.info(`Server started on port ${this.port}`);
                }
            });
        }
    }
    
    module.exports = StaticServer;

    在这个模块文件内,我们声明了一个StaticServer类,并给其定义了start方法,在该方法体内,创建了一个server对象,监听rquest事件,并将服务器绑定到配置文件指定的端口。在这个阶段,我们对于任何请求都暂时不作区分地简单地返回请求的文件路径。path模块用来规范化连接和解析路径,这样我们就不用特意来处理操作系统间的差异。

    app.js

    const StaticServer = require('./static-server');
    
    (new StaticServer()).start();

    在这个文件内,调用上面的static-server模块,并创建一个StaticServer实例,调用其start方法,启动了一个静态资源服务器。这个文件后面将不需要做其他修改,所有对静态资源服务器的完善都发生在static-server.js内。

    在目录下启动程序会看到成功启动的log:

    > node app.js
    
    Server started on port 9527

    在浏览器中访问,可以看到服务器将请求路径直接返回了。

    路由处理

    之前我们对任何请求都只是向客户端返回文件位置而已,现在我们将其替换成返回真正的文件:

        routeHandler(pathName, req, res) {
            
        }
    
        start() {
            http.createServer((req, res) => {
                const pathName = path.join(this.root, path.normalize(req.url));
                this.routeHandler(pathName, req, res);
            }).listen(this.port, err => {
                ...
            });
        }

    将由routeHandler来处理文件发送。

    读取静态文件

    读取文件之前,用fs.stat检测文件是否存在,如果文件不存在,回调函数会接收到错误,发送404响应。

       respondNotFound(req, res) {
            res.writeHead(404, {
                'Content-Type': 'text/html'
            });
            res.end(`<h1>Not Found</h1><p>The requested URL ${req.url} was not found on this server.</p>`);
        }
    
        respondFile(pathName, req, res) {
            const readStream = fs.createReadStream(pathName);
            readStream.pipe(res);
        }
    
        routeHandler(pathName, req, res) {
            fs.stat(pathName, (err, stat) => {
                if (!err) {
                    this.respondFile(pathName, req, res);
                } else {
                    this.respondNotFound(req, res);
                }
            });
        }

    Note:

    读取文件,这里用的是流的形式createReadStream而不是readFile,是因为后者会在得到完整文件内容之前将其先读到内存里。这样万一文件很大,再遇上多个请求同时访问,readFile就承受不来了。使用文件可读流,服务端不用等到数据完全加载到内存再发回给客户端,而是一边读一边发送分块响应。这时响应里会包含如下响应头:

    Transfer-Encoding:chunked

    默认情况下,可读流结束时,可写流的end()方法会被调用。

  • 相关阅读:
    JAVA数据结构--ArrayList动态数组
    LeetCode记录之35——Search Insert Position
    LeetCode记录之28——Implement strStr()
    LeetCode记录之27——Remove Element
    LeetCode记录之26——Remove Duplicates from Sorted Array
    LeetCode记录之21——Merge Two Sorted Lists
    LeetCode记录之20——Valid Parentheses
    LeetCode记录之14——Longest Common Prefix
    JMeter学习笔记01-安装环境
    Python3学习笔记35-编程练习题
  • 原文地址:https://www.cnblogs.com/xuxiaoyu/p/10512526.html
Copyright © 2020-2023  润新知