资讯专栏INFORMATION COLUMN

不使用框架创建简单的Node.js web应用

LeanCloud / 2183人阅读

摘要:不使用框架创建简单的应用需求创建一个可以上传图片的应用。自定义模块刚才我们定义了一个简单的服务。处理数据存储本地安装服务安装客户端使用命令行新建文件修改待续如何使用创建一个代理服务器的适用场景

不使用框架创建简单的Node.js web应用
需求: 创建一个可以上传图片的web应用。用户可以浏览应用,有一个文件上传的表单。选择图片上传,上传完成之后可以预览图片。上传的图片信息需要入库(mysql)。
一个简单的http服务
const http = require("http");
// 创建一个服务
const server  = http.createServer((req, res) => {
    res.writeHead(200, { "Content-Type": "text/plain" });
    res.end("Hello World");
});
// 服务错误监听
server.on("clientError", (err, socket) => {
    socket.end("HTTP/1.1 400 Bad Request

");
});
// 当前服务监听的端口
server.listen(8888);
console.log("Server has started.");

涉及到的api:
http.createServer
res.writeHead
res.end

当我们在编写node服务的时候,如果服务器有异常,那node服务就直接挂掉了。那如何保证我们的node服务不会关闭,并且会自动重启呢?
或者是我们修改了代码,如何实现修改的代码直接生效而不用重新手动重启node服务呢?

npm install -g nodemon

在生产环境我一般使用pm2来管理node服务。

自定义模块

刚才我们定义了一个简单的http服务。其中http是一个内置的模块。那其实我们的服务都会有一个入口文件,在这里我们定义为index.js。那我们如何像引用http内置模块一样,在index.js里使用server.js呢?

exports 与 module.exports 的区别:
exports是module.exports的简写。如果修改了exports的引用,也就是重新给exports赋值,则exports只是在当前文件级作用域内可用,并且exports的修改不会影响到module.exports的值。

server.js

const http = require("http");
function start() {
    const server  = http.createServer((req, res) => {
        res.writeHead(200, { "Content-Type": "text/plain" });
        res.end("Hello World");
    });
    server.on("clientError", (err, socket) => {
        socket.end("HTTP/1.1 400 Bad Request

");
    });
    server.listen(8888);
    console.log("Server has started.");
}
// 通过给exports添加【属性值】的方式导出方法
// 或者通过给module.exports添加属性值
exports.start = start;

index.js

const server = require("./server");
server.start();
node index.js
路由处理

我们知道,访问一个web网站会有不同的页面或者会调用不同的接口,那这些就对应这不同的请求路径,同时这些请求还会对应不同的请求方法(GET, POST等)。那node如何针对这些不同的请求路径去匹配对应的处理函数呢?

为了处理http请求的参数,我们需要获取到http请求的request,从中获取到请求方式以及请求路径。在这里会依赖 url内置模块。
首先建立routes文件夹存放路由处理

routes/index.js

module.exports = (req, res) => {
    res.writeHead(200, { "Content-Type": "text/plain" });
    res.end("Hello World");
}

routes/upload.js

module.exports = (req, res) => {
    res.writeHead(200, { "Content-Type": "text/plain" });
    res.end("upload file");
}

新建route.js文件处理路由

function route(handle, pathname, req, res) {
  if (typeof handle[pathname] === "function") {
    handle[pathname](req, res);
  } else {
    console.log("No request handler found for " + pathname);
    res.end("404 Not found");
  }
}
exports.route = route;

修改server.js

const http = require("http");
const url = require("url");
const routes = {};
function use(path, routeHandler) {
    routes[path] = routeHandler;
}
function start(route) {
    function handleRequest(req, res) {
        const pathname = url.parse(req.url).pathname;
        route(routes, pathname, req, res)
    }
    const server  = http.createServer(handleRequest);
    server.on("clientError", (err, socket) => {
        socket.end("HTTP/1.1 400 Bad Request

");
    });
    server.listen(8888);
    console.log("Server has started.");
}
module.exports = {
    start,
    use
};

修改index.js

const server = require("./server");
const index = require("./routes/index");
const upload = require("./routes/upload");
const router = require("./route");
server.use("/", index);
server.use("/upload", upload);
server.start(router.route);
处理POST请求

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

给request注册监听事件

request.addListener("data", function(chunk) {
  // called when a new chunk of data was received
});

request.addListener("end", function() {
  // called when all chunks of data have been received
});

querystring登场,解析上传数据

修改server.js里的handleRequest方法

function handleRequest(req, res) {
    const pathname = url.parse(req.url).pathname;
    let postData = "";
    // 设置编码
    req.setEncoding("utf8");
    req.addListener("data", function(postDataChunk) {
        postData += postDataChunk;
        console.log("Received POST data chunk ""+
        postDataChunk + "".");
    });

    req.addListener("end", function() {
        route(routes, pathname, req, res, postData);
    });
}

route.js多加一个参数postData

function route(handle, pathname, req, res, postData) {
  if (typeof handle[pathname] === "function") {
    handle[pathname](req, res, postData);
  } else {
    console.log("No request handler found for " + pathname);
    res.end("404 Not found");
  }
}
exports.route = route;

index.js

const exec = require("child_process").exec;
module.exports = (req, res, postData) => {
    // 可以使用node模板
    const body = ""+
    ""+
    ""+
    ""+
    ""+
    "
"+ ""+ ""+ "
"+ ""+ ""; res.end(body); }

upload.js 修改

const querystring = require("querystring");
module.exports = (req, res, postData) => {
    const content = querystring.parse(postData).text;
    res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8"});
    res.end(content || "Empty");
}
处理文件上传
npm install formidable

server.js修改

function handleRequest(req, res) {
    const pathname = url.parse(req.url).pathname;
    route(routes, pathname, req, res);
}

routes/index.js

const exec = require("child_process").exec;
module.exports = (req, res) => {
    // 可以使用node模板
    const body =  ""+
    ""+
    ""+
    ""+
    ""+
    "
"+ ""+ ""+ "
"+ ""+ ""; res.writeHead(200, {"Content-Type": "text/html; charset=utf-8"}); res.end(body); }

showFile.js获取磁盘图片信息

const fs = require("fs");
const path = require("path");

function show(req, res) {
    const rootPath = path.resolve();
  fs.readFile(`${rootPath}/tmp/test.png`, "binary", function(error, file) {
    if(error) {
      res.writeHead(500, {"Content-Type": "text/plain"});
      res.write(error + "
");
      res.end();
    } else {
      res.writeHead(200, {"Content-Type": "image/png"});
      res.write(file, "binary");
      res.end();
    }
  });
}

module.exports = show;

routes/uoload.js

const fs = require("fs");
const formidable = require("formidable");
const path = require("path");

module.exports = (req, res) => {
    const form = new formidable.IncomingForm();
    const rootPath = path.resolve();
    form.parse(req, function(error, fields, files) {
        console.log("parsing done");
        fs.renameSync(files.upload.path, `${rootPath}/tmp/test.png`);
        res.writeHead(200, {"Content-Type": "text/html;  charset=utf-8"});
        res.write("received image:
"); res.write(""); res.end(); }); }

同时在index.js中添加相应的路由。

处理数据存储

本地安装mysql服务
安装mysql客户端/使用命令行

npm install mysql
CREATE SCHEMA `nodestart` ;


CREATE TABLE `nodestart`.`file` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `filename` VARCHAR(300) NULL,
  `path` VARCHAR(500) NULL,
  `size` VARCHAR(45) NULL,
  `type` VARCHAR(45) NULL,
  `uploadtime` VARCHAR(45) NULL,
  PRIMARY KEY (`id`));

新建db.js文件

const mysql      = require("mysql");
const connection = mysql.createConnection({
  host     : "localhost",
  user     : "root",
  password : "123456",
  database : "nodestart"
});
function query(sql, params) {
    return new Promise((resolve, reject) => {
        connection.connect();
        connection.query(sql, params, function (error, results, fields) {
            if (error) reject(error);
            console.log("The solution is: ", results);
            resolve(fields);
        });
        connection.end();
    });
}
exports.query = query;

修改routes/upload.js

const fs = require("fs");
const formidable = require("formidable");
const path = require("path");
const db = require("../db");

module.exports = (req, res) => {
    const form = new formidable.IncomingForm();
    const rootPath = path.resolve();
    form.parse(req, function(error, fields, files) {
        console.log("parsing done");
        fs.renameSync(files.upload.path, `${rootPath}/tmp/test.png`);

        const fileObj = {
            size: files.upload.size,
            path: `${rootPath}/tmp/test.png`,
            filename: files.upload.name,
            type: files.upload.type,
            uploadtime: Date.now()
        }
        db.query("insert into nodestart.file set ?", fileObj).then((res) => {
            console.log(res)
        }).catch((err) => {
            console.log(err);
        })
        
        res.writeHead(200, {"Content-Type": "text/html;  charset=utf-8"});
        res.write("received image:
"); res.write(""); res.end(); }); }

待续:

如何使用Node创建一个代理服务器 Node 的适用场景

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/105738.html

相关文章

  • (译 & 转载) 2016 JavaScript 后起之秀

    摘要:在年成为最大赢家,赢得了实现的风暴之战。和他的竞争者位列第二没有前端开发者可以忽视和它的生态系统。他的杀手级特性是探测功能,通过检查任何用户的功能,以直观的方式让开发人员检查所有端点。 2016 JavaScript 后起之秀 本文转载自:众成翻译译者:zxhycxq链接:http://www.zcfy.cc/article/2410原文:https://risingstars2016...

    darry 评论0 收藏0
  • 2016-JavaScript之星

    摘要:在,是当之无愧的王者,赢得了与之间的战争,攻陷了的城池。于月发布了版本,这一版本为了更好的表现加入了渲染方式。前端框架这个前端框架清单可能是年疲劳的元凶之一。的创建者,目前在工作为寻找构建简单性和自主配置性之间的平衡做了很大的贡献。 春节后的第一篇就从这个开始吧~本文已在前端早读课公众号上首发 原文链接 JavasScript社区在创新的道路上开足了马力,曾经流行过的也许一个月之后就过...

    Binguner 评论0 收藏0
  • 2019,开发者应该学习16个JavaScript框架

    摘要:它不仅从前端移动到后端,我们也开始看到它用于机器学习和增强现实,简称。由于其高使用率,年的现状调查将其称为采用的安全技术。机器学习框架在年的开发者峰会上,宣布了他们的机器学习框架的实现,称为。更高级别的用于在之上构建机器学习模型。 2019,开发者应该学习的16个JavaScript框架 showImg(https://segmentfault.com/img/remote/14600...

    Harpsichord1207 评论0 收藏0
  • javascript功能插件大集合 前端常用插件 js常用插件

    摘要:转载来源包管理器管理着库,并提供读取和打包它们的工具。能构建更好应用的客户端包管理器。一个整合和的最佳思想,使开发者能快速方便地组织和编写前端代码的下一代包管理器。很棒的组件集合。隐秘地使用和用户数据。 转载来源:https://github.com/jobbole/aw... 包管理器管理着 javascript 库,并提供读取和打包它们的工具。•npm – npm 是 javasc...

    netmou 评论0 收藏0
  • javascript功能插件大集合 前端常用插件 js常用插件

    摘要:转载来源包管理器管理着库,并提供读取和打包它们的工具。能构建更好应用的客户端包管理器。一个整合和的最佳思想,使开发者能快速方便地组织和编写前端代码的下一代包管理器。很棒的组件集合。隐秘地使用和用户数据。 转载来源:https://github.com/jobbole/aw... 包管理器管理着 javascript 库,并提供读取和打包它们的工具。•npm – npm 是 javasc...

    Hydrogen 评论0 收藏0
  • javascript功能插件大集合,写前端亲们记得收藏

    摘要:一个专注于浏览器端和兼容的包管理器。一个整合和的最佳思想,使开发者能快速方便地组织和编写前端代码的下一代包管理器。完全插件化的工具,能在中识别和记录模式。健壮的优雅且功能丰富的模板引擎。完整的经过充分测试和记录数据结构的库。 【导读】:GitHub 上有一个 Awesome – XXX 系列的资源整理。awesome-javascript 是 sorrycc 发起维护的 JS 资源列表...

    cfanr 评论0 收藏0

发表评论

0条评论

LeanCloud

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<