Randolf's blog

用 Node.js 搭建本地服务器

2018-04-20
javascript
6分钟
1043字

Github

网友 bottle_ 提供搭建一个简单本地服务器的思路为下:

  • 我们需要一个 HTTP 服务器
  • 对于不同的请求,根据请求的 URL,我们的服务器需要给予不同的响应,因此我们需要一个路由,用于把请求对应到请求处理程序(request handler)
  • 当请求被服务器接收并通过路由传递之后,需要可以对其进行处理,因此我们需要最终的请求处理程序
  • 我们需要从 HTML 文件里提取数据以及展示服务器传入的数据,因此需要将 HTML 和服务器结合起来

首先需要两个文件 index.js 和 index.html。

  • index.js

    引用模块

    1
    const fs = require('fs'); // 系统文件及目录进行读写操作
    2
    const http = require('http'); // 封装了高效的 HTTP 服务器和 HTTP 客户端
    3
    const url = require('url'); // URL 处理

    路由

    1
    /**
    2
    * 路由
    3
    * @param {Function} handle 请求处理程序
    4
    * @param {String} pathname 路径
    5
    * @param {Object} response 响应数据
    6
    * @param {Object} postData 请求参数
    7
    */
    8
    function route(handle, pathname, response, postData) {
    9
    if (typeof handle[pathname] === 'function') {
    10
    handle[pathname](response, postData);
    11
    } else {
    12
    response.writeHead(404, { 'Content-Type': 'text/plain' });
    13
    response.write('404 Not Found');
    14
    response.end();
    15
    }
    1 collapsed line
    16
    }

    服务器

    1
    /**
    2
    * 服务器
    3
    * @param {Function} route 路由
    4
    * @param {Function} handle 请求处理程序
    5
    */
    6
    function start(route, handle) {
    7
    function onRequest(request, response) {
    8
    const pathname = url.parse(request.url).pathname;
    9
    let postData = '';
    10
    switch (request.method) {
    11
    case 'GET':
    12
    postData += url.parse(request.url).query;
    13
    request.setEncoding('utf8');
    14
    route(handle, pathname, response, postData);
    15
    break;
    14 collapsed lines
    16
    case 'POST':
    17
    request.addListener('data', function (postDateChunk) {
    18
    postData += postDateChunk;
    19
    });
    20
    request.addListener('end', function () {
    21
    route(handle, pathname, response, postData);
    22
    });
    23
    break;
    24
    };
    25
    }
    26
    27
    http.createServer(onRequest).listen(8080);
    28
    console.log('Server has started');
    29
    }

    请求处理程序

    1
    // 请求处理程序
    2
    const handle = {
    3
    // index 接口
    4
    '/public/index.html': function (response, postData) {
    5
    const pathname = __dirname + '/public/index.html';
    6
    fs.readFile(pathname, function (err, data) {
    7
    response.end(data);
    8
    });
    9
    },
    10
    // download 接口
    11
    '/download': function (response, postData) {
    12
    response.writeHead(200, { 'Content-Type': 'text/html' });
    13
    response.write(JSON.stringify({
    14
    code: 200,
    15
    data: {
    12 collapsed lines
    16
    'time': new Date().toLocaleString("en-US")
    17
    }
    18
    }));
    19
    response.end();
    20
    },
    21
    // upload 接口
    22
    '/upload': function (response, postData) {
    23
    response.writeHead(200, { 'Content-Type': 'text/html' });
    24
    response.write('You have sent: ' + JSON.parse(postData).value);
    25
    response.end();
    26
    }
    27
    };

    启动服务器

    1
    // 启动服务器 = 路由处理 + 接口处理
    2
    start(route, handle);
  • index.html

    1
    <!DOCTYPE html>
    2
    <html lang="en">
    3
    4
    <head>
    5
    <meta charset="UTF-8">
    6
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    8
    <title>Document</title>
    9
    </head>
    10
    11
    <body>
    12
    <input type="text" name="input">
    13
    <button value="submit" name="submit">submit</button>
    14
    <p></p>
    15
    <!-- submit demo -->
    33 collapsed lines
    16
    <script>
    17
    const btn = document.querySelector('button');
    18
    btn.addEventListener('click', function () {
    19
    const value = document.querySelector('input').value;
    20
    ajax(value);
    21
    }, true);
    22
    23
    function ajax(value) {
    24
    const xmlhttp;
    25
    if (window.XMLHttpRequest) {
    26
    xmlhttp = new XMLHttpRequest();
    27
    } else {
    28
    xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
    29
    }
    30
    31
    xmlhttp.onreadystatechange = function () {
    32
    if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
    33
    document.querySelector('p').innerHTML = xmlhttp.responseText;
    34
    }
    35
    }
    36
    37
    xmlhttp.open('POST', '/upload', true);
    38
    xmlhttp.send(JSON.stringify({
    39
    value: value
    40
    }));
    41
    42
    // xmlhttp.open('GET', '/upload?value='+value, true);
    43
    // xmlhttp.send();
    44
    }
    45
    </script>
    46
    </body>
    47
    48
    </html>

注意事项:

  • 关于 GET 和 POST 方式的请求参数

    GET 的请求参数是以查询参数形式放在 URL 后面的,服务器可以从 URL 上获取参数:url.parse(request.url).query

    POST 的请求参数则需要作为 xhr.send() 的参数并转换为字符串来传递,本文使用 JSON.stringify() 来转换,再在服务器端用 JSON.parse() 转换。

    服务器端在响应两种请求方式时,响应数据格式参考官方文档

  • 关于服务器响应头中的 Content-Type

    一般网站的做法是:当返回 HTML 页面时为 text/html,当使用 JSONP 时为 text/javascript,当使用 CORS 时为 application/json。

  • 关于跨域

    如果希望某个接口可以跨域,需要设置响应头的 Access-Control-Allow-Origin*,比如允许 download 接口跨域,代码修改如下:

    Terminal window
    1
    response.writeHead(200, { 'Content-Type': 'text/html', 'Access-Control-Allow-Origin': '*' });

    调试的话,只要启动两个不同端口的 index.js 即可,代码仓库里 server.1.js 和 server.2.js 就表示两个不同的 index.js。

  • 关于 Node.js 热部署

    Node.js 启动服务器时是将脚本放入内存,以后都会直接访问内存,避免重复载入。这种设计虽然有利于提高性能,却不利于开发调试,导致修改 Node.js 代码后需要手动终止进程并重启才会生效。

    网友 会奔跑的胖子 提出方案:

    你只需要在修改文件后保存,它就能自动替你发布,这就是所谓的热部署。

    supervisor 就是一个 Node.js 的开源热部署工具:

    Terminal window
    1
    npm i supervisor -g
    2
    supervisor server.js

    该网友中还提到另一个开源热部署工具 hotcode,但经测试 hotcode 若使用 express 4.x 则会报错,因为 hotcode 使用的 express.createServer() 已经被废弃。

参考:

学习笔记:用Nodejs搭建一个简单的本地服务器
NodeJS”热部署“代码,实现动态调试(hotnode,可以实现热更新)

本文标题:用 Node.js 搭建本地服务器
文章作者:Randolf Zhang
发布时间:2018-04-20
Copyright 2025
站点地图