[Node入门] => 读书笔记(二)

相关笔记

  1. [Node入门] => 读书笔记(一)

学习内容

  1. Node入门

学习笔记

1. 以非阻塞操作进行请求响应

直接借用原标题,这部分我觉得属于NodeJs的特点。毕竟,其以异步非阻塞而闻名,虽然到现在为止,我还不太了解到底是什么意思,最直接的感受就是,在此之前,我一直以为非阻塞属于nodejs必然的,并没有想到,需要自己去实现,不去通过回调函数实现,nodejs一样会阻塞。

[Node入门] 现在我们采用如下这种新的实现方式:相对采用将内容传递给服务器的方式,我们这次采用将服务器“传递”给内容的方式。 从实践角度来说,就是将response对象(从服务器的回调函数onRequest()获取)通过请求路由传递给请求处理程序。 随后,处理程序就可以采用该对象上的函数来对请求作出响应。

简单来说,将response作为参数从服务器模块(server.js)传递给路由模块(router.js),再进入请求处理模块(requestHandlers.js)生成对应的response。

如下代码:

/* [index.js]  主文件 */
var server = require('./server.js');
var router = require('./router.js');
var requestHandlers = require('./requestHandlers.js');

var handles = {};
handles['/'] = requestHandlers.start;
handles['/start'] = requestHandlers.start;
handles['/upload'] = requestHandlers.upload;
handles['/sleep'] = requestHandlers.sleep;

server.start(router.route, handles);
/* [server.js] 服务器模块 */
const http = require('http'); // 使用require指令载入http模块
const url = require('url'); // 载入url模块
const hostname = '127.0.0.1'; // 创建主机名
const port = 1337; // 创建端口

function start(route, handles) {
    http.createServer((request, response) => {
        var pathname = url.parse(request.url).pathname;
        console.log(`Request for ${pathname} received.`);
        route(handles, pathname, response);
    }).listen(port, hostname, () => {
        console.log(`Server running at http://${hostname}:${port}/`);
    });
}
exports.start = start;
/* [router.js] 路由模块 */
function route(handle, pathname, response) {
    console.log(`About to route a request for ${pathname}`);
    // 判断是否存在路径名,不存在则返回404错误
    if (typeof handle[pathname] === 'function') {
        handle[pathname](response); 
    } else {
        console.log(`No request handler found for ${pathname}`);
        response.writeHead(404, {'Context-Type' : 'text/plain'});
        response.end('404 NOT FOUND');
    }
}
exports.route = route;
/* [requestHandlers.js] 请求处理模块 */
// 导入child_process模块的exec方法,使用该方法尝试非阻塞操作
const exec = require('child_process').exec;

// 非阻塞操作
function start(response) {
    console.log('Request handler "start" was called!');
    // 异步非阻塞操作
    exec('find /', 
        // 提供十秒的延迟
        { timeout: 10000, maxBuffer: 20000 * 1024 }, 
        // 异步非阻塞的核心,回调函数
        (error, stdout, stderr) => {
            response.writeHead(200, { 'Content-Type': 'text/plain' });
            response.end(stdout);
        });
}

function upload(response) {
    console.log('Request handler "upload" was called!');
    response.writeHead(200, { 'Content-Type': 'text/plain' });
    response.end('Hello Upload!');
}

// 阻塞操作
function sleep(response) {
    var sleepTime = 10000, // 休眠时间
        startTime = new Date().getTime();
    // 休眠sleepTime毫秒,将会阻塞服务器10秒
    while (new Date().getTime() < startTime + sleepTime);
    response.writeHead(200, { 'Content-Type': 'text/plain' });
    response.end(`Hello sleep ${sleepTime / 1000} seconds!`);
}

exports.start = start;
exports.upload = upload;
exports.sleep = sleep;

解释:在requestHandlers.js中,start()与sleep()方法的对比,可以通过进行对照试验了解。
1. 先开http://127.0.0.1:1337/start,后开http://127.0.0.1:1337/upload
2. 先开http://127.0.0.1:1337/sleep, 后开http://127.0.0.1:1337/upload
第一组中,start网页需要等待十秒,而upload网页能够立即得到响应;
第二组中,sleep网页同样需要等待十秒,同时阻塞了upload网页的响应。

2. 处理POST请求

实现这样一个需求:我们显示一个文本区(textarea)供用户输入内容,然后通过POST请求提交给服务器。最后,服务器接受到请求,通过处理程序将输入的内容展示到浏览器中。

/* [index.js]  主文件 */
const server = require('./server.js'); // 导入服务器模块
const router = require('./router.js'); // 导入路由模块
const requestHandlers = require('./requestHandlers.js'); // 导入请求处理模块

const handle = {}; // 创建请求对象
handle['/'] = requestHandlers.start;
handle['/start'] = requestHandlers.start;
handle['/upload'] = requestHandlers.upload;

server.start(router.route, handle);

服务器模块:与上一节对比,多了一项对于返回数据的处理,这是因为

[Node入门] 为了使整个过程非阻塞,Node.js会将POST数据拆分成很多小的数据块,然后通过触发特定的事件,将这些小数据块传递给回调函数。这里的特定的事件有data事件(表示新的小数据块到达了)以及end事件(表示所有的数据都已经接收完毕)。

/* [server.js] 服务器模块 */
const http = require('http'); // 使用require指令载入http模块
const url = require('url'); // 载入url模块

const hostname = '127.0.0.1'; // 创建主机名
const port = 1337; // 创建端口

function start(route, handle) {
    http.createServer((request, response) => {
        var postData = '';
        // 获取请求中的url路径
        var pathname = url.parse(request.url).pathname;
        console.log(`Request for ${pathname} received.`);

        // 设置接受的数据编码格式为UTF-8
        request.setEncoding('utf8');
        // 监听请求的‘data’事件
        // 因为接受的数据可能会很大,为了使整个过程非阻塞,Node.js会将POST数据拆分成很多小的数据块
        request.on('data', postDataChunk => postData += postDataChunk);
        // 监听请求的‘end’事件,确保它只会当所有数据接受完毕后才触发
        request.on('end', () => route(handle, pathname, response, postData));

    }).listen(port, hostname, () => { // 监听主机,端口
        console.log(`Server running at http://${hostname}:${port}/`);
    });
}

exports.start = start;

请求处理模块: /start 返回了一个包含文本区的html,并在点击上传后,将数据显示到 /upload。

/* [requestHandlers.js] 请求处理模块 */
const querystring = require('querystring');

function start(response, postData) {
    console.log('Request handler "start" was called!');

    var body = `<!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>Node入门-图片上传</title>
    </head>
    <body>
        <form action="/upload" method="post">
            <textarea name="text" rows="20" cols="60"></textarea>
            <input type="submit" value="上传"></input>
        </form>
    </body>
    </html>
    `;

    response.writeHead(200, { 'Content-Type' : 'text/html'});
    response.end(body);
}

function upload(response, postData) {
    console.log('Request handler "upload" was called!');
    response.writeHead(200, {
        'Content-Type': 'text/html;charset=utf-8'
    });
    response.end(`您刚刚发送的内容为:${querystring.parse(postData).text}`);
}

exports.start = start;
exports.upload = upload;
/* [router.js] 路由模块 */
function route(handle, pathname, response, postData) {
    console.log(`About to route a request for ${pathname}`);
    // 判断是否存在路径名,不存在则返回404错误
    if (typeof handle[pathname] === 'function') {
        handle[pathname](response, postData); 
    } else {
        console.log(`No request handler found for ${pathname}`);
        response.writeHead(404, {'Context-Type' : 'text/plain'});
        response.end('404 NOT FOUND');
    }
}

exports.route = route;

注意:这里有两点需要注意:
1. request的编码格式要设置成”utf8”;
2. 因为post请求是通过URL,因此需要对传入的postData进行URL解码,使用querystring模块的parse()方法(NodeAPI)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值