试试用 Node.js 编写个简单的web框架

简介: 今天跟往常一样逛技术社区,发现了一篇《Express 简单实现》(github) ,写的还是比较简单易懂的。刚好平时在测试比如局域网共享文件,临时网页共享或测试等等情况下可能会需要一个临时的http服务。

今天跟往常一样逛技术社区,发现了一篇《Express 简单实现》(github) ,写的还是比较简单易懂的。
刚好平时在测试比如局域网共享文件,临时网页共享或测试等等情况下可能会需要一个临时的http服务。
当然一般情况下我都是使用Python命令python -m http.server 8080来做临时服务,但是如果需要有动态请求时可能就不能用这种办法了(当然啦你也可以使用PythonBottle库或Node.jsExpress来编写临时服务) 。
刚好那就自己也尝试着写写一个简单的web框架呗。

1.一个很简单的示例

simple_http.js

const http = require('http');
const url = require('url');
const fs = require('fs');

var routes = {//路由
    '/'(req, res) {
        res.end('关爱单身狗成长协会');
    },
    '/demo'(req, res) { //读取html示例
        res.write(fs.readFileSync('./demo.html', 'utf-8'));
        res.end();
    },
    /** 自定义路由.... **/
    err(req, res, errCode) {//自定义异常
        res.writeHead(errCode, { 'Content-Type': 'text/html' });
        res.write(errCode.toString());
        res.end();
    }
};

http.createServer((req, res) => {//监听
    let { pathname } = url.parse(req.url, true);//获取访问路径
    let route = routes[pathname];//匹配路由
    try {
        return route ? route(req, res) : routes.err(req, res, 400);
    }
    catch (err) {
        console.error(err);
        routes.err(req, res, 500);
    }
}).listen(8080);

2.将其包装成库

simple_http.js

'use strict';
const http = require('http');
const url = require('url');
function createApplication() {
    let app = function (req, res) {//监听
        let { pathname } = url.parse(req.url, true);//获取访问路径
        let route = app.routes[pathname];
        let r = { "req": req, "res": res, "path": pathname, "app": app, method: req.method.toLocaleUpperCase() };
        try {
            return route ? route.apply(r) : app.error404(r);
        }
        catch (err) {
            app.error(Object.assign(r, { err: err.toString(), errCode: 500 }));
        }
    };
    app.routes = {};//路由
    app.error = (r) => {//异常处理
        console.error(r);
        r.res.writeHead(r.errCode, { 'Content-Type': 'text/html' });
        r.res.write(r.errCode.toString());
        r.res.end();
    };
    app.error404 = (r) => app.error(Object.assign(r, { err: "path not find", errCode: 404 }));//404异常处理
    app.listen = function () {
        let server = http.createServer(app);
        server.listen(...arguments);
        return server;
    };
    return app;
}
module.exports = createApplication;

app.js调用:

const app = require("./simple_http")();
const fs = require('fs');

app.routes["/"] = function () {
    this.res.end('关爱单身狗成长协会');
};
app.routes["/demo"] = function () { 
    this.res.write(fs.readFileSync('./demo.html', 'utf-8'));
    this.res.end();
};

let server = app.listen(8080, '0.0.0.0', function () {
    console.log(`listening at http://${server.address().address}:${server.address().port}`)
});

3.增加静态文件夹访问,控制台异常信息输出

simple_http.js

'use strict';
const http = require('http')
const url = require('url')
const utils = require("./utils");
function createApplication() {
    let app = function (req, res) {
        // 解析请求,包括文件名
        let { pathname } = url.parse(req.url, true);
        let route = app.routes[pathname];
        let r = { "req": req, "res": res, "path": pathname, "app": app, method: req.method.toLocaleUpperCase() };
        try {
            return route ? route.apply(r) :app.serve(r, (e, res) => {if (e && e.status) app.error404(r);});
        }
        catch (err) {
            app.error(Object.assign(r, { err: err.toString(), errCode: 500 }));
        }
    };
    app.routes = {};
    app.error = (r) => r.res.end();
    app.error404 = (r) => app.error(Object.assign(r, { err: "path not find", errCode: 404 }));
    app.listen = function () {
        let server = http.createServer(app);
        server.listen(...arguments);
        return server;
    };
    return utils(app);
}
module.exports = createApplication;

utils.js扩展:

const mime = require("./mime");
const fs = require("fs");
module.exports = function (app) {
    app.getClientIP = (req) => req.headers['x-real-ip'] || req.headers['x-forwarded-for']|| req.connection.remoteAddress;
    app.errorLog = (r) => console.error({ "path": r.path, "ip": app.getClientIP(r.req), err: r.err, errCode: r.errCode });
    app.error = (r) => {
        app.errorLog(r);
        r.res.writeHead(r.errCode, { 'Content-Type': 'text/html' });
        r.res.write(r.errCode.toString());
        r.res.end();
    };
    app.static = [];
    app.serve = (r) => {
        let path = r.path.replace(/^\/+/, "");
        if (app.static.length == 0) return app.error404(r);
        let s = app.static.find(_ => path.indexOf(_) == 0);
        if (s) {
            let t = mime.getType(path);
            return fs.readFile(path, function (err, fr) {
                if (err) {
                    app.error404(r);
                } else {
                    r.res.writeHead(200, { 'Content-Type': t });
                    r.res.write(fr);
                    r.res.end();
                }
            });
        }
    };
    app.moveFile = (op, np) => fs.renameSync(op, np);
    app.copyFile = (op, np) => fs.writeFileSync(np, fs.readFileSync(op));
    app.readJSON = (p) => JSON.parse(fs.readFileSync(p));
    app.writeJSON = (p, d) => fs.writeFileSync(p, JSON.stringify(d));
    app.readText = (p) => fs.readFileSync(p, 'utf-8');
    return app;
};

mime.js文件扩展名识别

const M = {
    getType(p) {
        let e = p.toLocaleLowerCase().split(".");
        return M[e[e.length - 1]] || M["*"];
    }, 
    "*": "application/octet-stream", 
    "tif": "image/tiff",
    //.........
    "css": "text/css",
    //.........
    "htm": "text/html",
    "html": "text/html",
    //.........
    "jpeg": "image/jpeg",
    "jpg": "image/jpeg", 
    "js": "application/javascript",
    "json":"application/json",
    //.........
    };
module.exports = M;

app.js调用:

const app = require("./simple_http")();
const fs = require('fs');

app.static.push("static");//加入静态目录

app.routes["/"] = function () {//加入路由
    this.res.end('关爱单身狗成长协会');
};

let server = app.listen(8080, '0.0.0.0', function () {
    console.log(`listening at http://${server.address().address}:${server.address().port}`)
});

好啦一个简单的web框架,就写的差不多了。大家可以参考着写写看,或比如加入:正则路由解析、模板引擎、post请求处理、文件上传处理等等的功能。
文章源码放在:https://gitee.com/baojuhua/node_simple_http/tree/master

相关文章
|
1月前
|
存储 缓存 JavaScript
node 框架
Node 框架以其独特的优势和广泛的应用场景,成为了现代 Web 开发中不可或缺的一部分。掌握 Node 框架的开发技能,对于开发者来说具有重要的意义。
102 59
|
1月前
|
Web App开发 JavaScript 前端开发
深入浅出Node.js后端框架
【10月更文挑战第34天】在数字化时代,后端开发如同一座桥梁,连接着用户界面与数据处理的两端。本文将通过Node.js这一轻量级、高效的平台,带领读者领略后端框架的魅力。我们将从基础概念出发,逐步深入到实战应用,最后探讨如何通过代码示例来巩固学习成果,使读者能够在理论与实践之间架起自己的桥梁。
|
1月前
|
Web App开发 缓存 监控
如何解决Node框架中内存管理的挑战?
解决 Node 框架中内存管理的挑战需要综合运用多种方法,并且需要在开发过程中保持谨慎和细心,不断优化和改进代码。同时,定期进行内存管理的检查和维护也是非常重要的。
111 63
|
1月前
|
安全 前端开发 JavaScript
Node框架的优缺点
Node 框架的优点使其在现代 Web 开发中具有重要地位,但同时也需要开发者在使用过程中注意其缺点,合理选择和应用,以充分发挥其优势,避免潜在问题的出现。随着技术的不断发展和完善,Node 框架也在不断改进和优化,以更好地适应各种应用需求。
88 47
|
27天前
|
JavaScript
使用Node.js创建一个简单的Web服务器
使用Node.js创建一个简单的Web服务器
|
1月前
|
机器学习/深度学习 人工智能 JavaScript
JavaScript和TypeScript的未来发展趋势及其在Web开发中的应用前景
本文探讨了JavaScript和TypeScript的未来发展趋势及其在Web开发中的应用前景。JavaScript将注重性能优化、跨平台开发、AI融合及WebAssembly整合;TypeScript则强调与框架整合、强类型检查、前端工程化及WebAssembly的深度结合。两者结合发展,特别是在Vue 3.0中完全采用TypeScript编写,预示着未来的Web开发将更加高效、可靠。
42 4
|
1月前
|
开发框架 搜索推荐 数据可视化
Django框架适合开发哪种类型的Web应用程序?
Django 框架凭借其强大的功能、稳定性和可扩展性,几乎可以适应各种类型的 Web 应用程序开发需求。无论是简单的网站还是复杂的企业级系统,Django 都能提供可靠的支持,帮助开发者快速构建高质量的应用。同时,其活跃的社区和丰富的资源也为开发者在项目实施过程中提供了有力的保障。
|
1月前
|
开发框架 JavaScript 前端开发
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势。通过明确的类型定义,TypeScript 能够在编码阶段发现潜在错误,提高代码质量;支持组件的清晰定义与复用,增强代码的可维护性;与 React、Vue 等框架结合,提供更佳的开发体验;适用于大型项目,优化代码结构和性能。随着 Web 技术的发展,TypeScript 的应用前景广阔,将继续引领 Web 开发的新趋势。
38 2
|
1月前
|
缓存 负载均衡 JavaScript
构建高效后端服务:Node.js与Express框架实践
在数字化时代的浪潮中,后端服务的重要性不言而喻。本文将通过深入浅出的方式介绍如何利用Node.js及其强大的Express框架来搭建一个高效的后端服务。我们将从零开始,逐步深入,不仅涉及基础的代码编写,更会探讨如何优化性能和处理高并发场景。无论你是后端新手还是希望提高现有技能的开发者,这篇文章都将为你提供宝贵的知识和启示。
|
1月前
|
存储 JavaScript 搜索推荐
Node框架的安装和配置方法
安装 Node 框架是进行 Node 开发的第一步,通过正确的安装和配置,可以为后续的开发工作提供良好的基础。在安装过程中,需要仔细阅读相关文档和提示,遇到问题及时解决,以确保安装顺利完成。
93 2