完全基于node的web应用
完全基于node的web应用
事实上通常“正确的方式”一般都不简单。
这其中涉及了nodejs中服务端JavaScript,函数式编程,阻塞与非阻塞,回调,事件,内部和外部模块等问题,但是函数式编程,阻塞与非阻塞,回调,事件这些编程思想是通用的,值得学习。
Node入门
用例
用户可以通过浏览器使用我们的应用。
当用户请求http://domain/start时,可以看到一个欢迎页面,页面上有一个文件上传的表单。
用户可以选择一个图片并提交表单,随后文件将被上传到http://domain/upload,该页面完成上传后会把图片显示在页面上。
模块
提供一个web页面,需要
http服务器。需要一个
路由处理URL请求,对应到请求处理程序(requet handle)。路由处理POST数据,把数据封装好后传递给请求处理程序。
最终的请求处理程序。
返回一个对应视图给浏览器。
上传功能。
基本http服务器
server.js
- var http = require ("http");
- http.createServer(function (request,response){
- response.writeHead(200,{"Content-Type":"text/plain"});
- response.write("hello world");
- response.end();
- }).listen(8888);
- var http = require ("http");
基于事件驱动回调
server.js
- var http = require("http");
- //这是一个事件回调函数
- function onRequest(request, response) {
- console.log("Request received.");
- response.writeHead(200, {"Content-Type": "text/plain"});
- response.write("Hello World");
- response.end();
- }
- //一旦由请求事件,onRequest函数被调用
- http.createServer(onRequest).listen(8888);
- console.log("Server has started.");
模块化server
server.js
- var http = require("http");
- function start() {
- function onRequest(request, response) {
- console.log("Request received.");
- response.writeHead(200, {"Content-Type": "text/plain"});
- response.write("Hello World");
- response.end();
- }
- http.createServer(onRequest).listen(8888);
- console.log("Server has started.");
- }
- //导出函数
- exports.start = start;
- var http = require("http");
路由模块,依赖注入到service
router.js
- function route(pathname) {
- console.log("About to route a request for " + pathname);
- }
- exports.route = route;
- function route(pathname) {
server.js
- var http = require("http");
- var url = require("url");
- function start(route) {
- function onRequest(request, response) {
- var pathname = url.parse(request.url).pathname;
- console.log("Request for " + pathname + " received.");
- route(pathname);//依赖注入
- response.writeHead(200, {"Content-Type": "text/plain"});
- response.write("Hello World");
- response.end();
- }
- http.createServer(onRequest).listen(8888);
- console.log("Server has started.");
- }
- exports.start = start;
- var http = require("http");
index.js
- var server = require("./server");
- var router = require("./router");
- server.start(router.route);//依赖注入
行为驱动处理函数,函数式编程
requestHandlers.js
- //行为实现
- function start() {
- console.log("Request handler 'start' was called.");
- return "Hello Start";
- }
- function upload() {
- console.log("Request handler 'upload' was called.");
- return "Hello Upload";
- }
- exports.start = start;
- exports.upload = upload;
- //行为实现
index.js
- var server = require("./server");
- var router = require("./router");
- var requestHandlers = require("./requestHandlers");
- var handle = {}//根据路由执行行为定义
- handle["/"] = requestHandlers.start;
- handle["/start"] = requestHandlers.start;
- handle["/upload"] = requestHandlers.upload;
- server.start(router.route, handle);
- var server = require("./server");
server.js
- var http = require("http");
- var url = require("url");
- function start(route, handle) {
- function onRequest(request, response) {
- var pathname = url.parse(request.url).pathname;
- console.log("Request for " + pathname + " received.");
- response.writeHead(200, {"Content-Type": "text/plain"});
- var content = route(handle, pathname) //路由行为分配
- response.write(content);
- response.end();
- }
- http.createServer(onRequest).listen(8888);
- console.log("Server has started.");
- }
- exports.start = start;
- var http = require("http");
router.js
- function route(handle, pathname) {
- console.log("About to route a request for " + pathname);
- //根据路由分配行为
- if (typeof handle[pathname] === 'function') {
- return handle[pathname]();
- } else {
- console.log("No request handler found for " + pathname);
- return "404 Not found";
- }
- }
- exports.route = route;
- function route(handle, pathname) {
阻塞与非阻塞
nodeJS它通过事件轮询(event loop)来实现并行操作,所以尽可能的避免阻塞操作,取而代之,多使用非阻塞操作。
要用非阻塞操作,我们需要使用回调。
回调就是:你继续处理你的事情,我(Node.js线程)先不等你了,我继续去处理你后面的代码,请你提供一个callbackFunction(),等你处理完之后我会去调用该回调函数的,谢谢!
阻塞的请求
requestHandlers.js
- function start() {
- console.log("Request handler 'start' was called.");
- function sleep(milliSeconds) {
- var startTime = new Date().getTime();
- while (new Date().getTime() < startTime + milliSeconds);
- }
- sleep(10000);
- return "Hello Start";
- }
- function upload() {
- console.log("Request handler 'upload' was called.");
- return "Hello Upload";
- }
- exports.start = start;
- exports.upload = upload;
处理POST请求
requestHandlers.js
- function start(response) {
- console.log("Request handler 'start' was called.");
- var body = '<html>'+
- '<head>'+
- '<meta http-equiv="Content-Type" content="text/html; '+
- 'charset=UTF-8" />'+
- '</head>'+
- '<body>'+
- '<form action="/upload" method="post">'+
- '<textarea name="text" rows="20" cols="60"></textarea>'+
- '<input type="submit" value="Submit text" />'+
- '</form>'+
- '</body>'+
- '</html>';
- response.writeHead(200, {"Content-Type": "text/html"});
- response.write(body);
- response.end();
- }
- function upload(response) {
- console.log("Request handler 'upload' was called.");
- response.writeHead(200, {"Content-Type": "text/plain"});
- response.write("Hello Upload");
- response.end();
- }
- exports.start = start;
- exports.upload = upload;
- function start(response) {
request监听器
server.js
- var http = require("http");
- var url = require("url");
- function start(route, handle) {
- function onRequest(request, response) {
- var postData = "";//传输的数据
- var pathname = url.parse(request.url).pathname;
- console.log("Request for " + pathname + " received.");
- request.setEncoding("utf8");
- //监听数据传输
- request.addListener("data", function(postDataChunk) {
- postData += postDataChunk;
- console.log("Received POST data chunk '"+
- postDataChunk + "'.");
- });
- //传输结束一次处理
- request.addListener("end", function() {
- route(handle, pathname, response, postData);
- });
- }
- http.createServer(onRequest).listen(8888);
- console.log("Server has started.");
- }
- exports.start = start;
- var http = require("http");
数据传输给路由
router.js
- function route(handle, pathname, response, postData) {
- console.log("About to route a request for " + pathname);
- if (typeof handle[pathname] === 'function') {
- handle[pathname](response, postData);
- } else {
- console.log("No request handler found for " + pathname);
- response.writeHead(404, {"Content-Type": "text/plain"});
- response.write("404 Not found");
- response.end();
- }
- }
- exports.route = route;
- function route(handle, pathname, response, postData) {
响应请求
requestHandlers.js
- var querystring = require("querystring");
- function start(response, postData) {
- console.log("Request handler 'start' was called.");
- var body = '<html>'+
- '<head>'+
- '<meta http-equiv="Content-Type" content="text/html; '+
- 'charset=UTF-8" />'+
- '</head>'+
- '<body>'+
- '<form action="/upload" method="post">'+
- '<textarea name="text" rows="20" cols="60"></textarea>'+
- '<input type="submit" value="Submit text" />'+
- '</form>'+
- '</body>'+
- '</html>';
- response.writeHead(200, {"Content-Type": "text/html"});
- response.write(body);
- response.end();
- }
- function upload(response, postData) {
- console.log("Request handler 'upload' was called.");
- response.writeHead(200, {"Content-Type": "text/plain"});
- response.write("You've sent the text: "+
- querystring.parse(postData).text);
- response.end();
- }
- exports.start = start;
- exports.upload = upload;
- var querystring = require("querystring");
使用外部模块上传文件
node-formidable模块 安装
npm insatll formidable
npm install formidable -g express -d
node-formidable官方的例子
var formidable = require('formidable'),
http = require('http'),
util = require('util');
http.createServer(function(req, res) {
if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
// parse a file upload
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received upload:\n\n');
res.end(util.inspect({fields: fields, files: files}));
});
return;
}
// show a file upload form
res.writeHead(200, {'content-type': 'text/html'});
res.end(
'<form action="/upload" enctype="multipart/form-data" '+
'method="post">'+
'<input type="text" name="title"><br>'+
'<input type="file" name="upload" multiple="multiple"><br>'+
'<input type="submit" value="Upload">'+
'</form>'
);
}).listen(8888);
读取图片数据
requestHandlers.js
- var querystring = require("querystring"),
- fs = require("fs");
- function start(response, postData) {
- console.log("Request handler 'start' was called.");
- var body = '<html>'+
- '<head>'+
- '<meta http-equiv="Content-Type" '+
- 'content="text/html; charset=UTF-8" />'+
- '</head>'+
- '<body>'+
- '<form action="/upload" method="post">'+
- '<textarea name="text" rows="20" cols="60"></textarea>'+
- '<input type="submit" value="Submit text" />'+
- '</form>'+
- '</body>'+
- '</html>';
- response.writeHead(200, {"Content-Type": "text/html"});
- response.write(body);
- response.end();
- }
- function upload(response, postData) {
- console.log("Request handler 'upload' was called.");
- response.writeHead(200, {"Content-Type": "text/plain"});
- response.write("You've sent the text: "+
- querystring.parse(postData).text);
- response.end();
- }
- function show(response, postData) {
- console.log("Request handler 'show' was called.");
- fs.readFile("/tmp/test.png", "binary", function(error, file) {
- if(error) {
- response.writeHead(500, {"Content-Type": "text/plain"});
- response.write(error + "\n");
- response.end();
- } else {
- response.writeHead(200, {"Content-Type": "image/png"});
- response.write(file, "binary");
- response.end();
- }
- });
- }
- exports.start = start;
- exports.upload = upload;
- exports.show = show;
- var querystring = require("querystring"),
index.js
- var server = require("./server");
- var router = require("./router");
- var requestHandlers = require("./requestHandlers");
- var handle = {}
- handle["/"] = requestHandlers.start;
- handle["/start"] = requestHandlers.start;
- handle["/upload"] = requestHandlers.upload;
- handle["/show"] = requestHandlers.show;
- server.start(router.route, handle);
- var server = require("./server");
上传图片
requestHandlers.js
- var querystring = require("querystring"),
- fs = require("fs"),
- formidable = require("formidable");
- function start(response) {
- console.log("Request handler 'start' was called.");
- var body = '<html>'+
- '<head>'+
- '<meta http-equiv="Content-Type" content="text/html; '+
- 'charset=UTF-8" />'+
- '</head>'+
- '<body>'+
- '<form action="/upload" enctype="multipart/form-data" '+
- 'method="post">'+
- '<input type="file" name="upload" multiple="multiple">'+
- '<input type="submit" value="Upload file" />'+
- '</form>'+
- '</body>'+
- '</html>';
- response.writeHead(200, {"Content-Type": "text/html"});
- response.write(body);
- response.end();
- }
- function upload(response, request) {
- console.log("Request handler 'upload' was called.");
- var form = new formidable.IncomingForm();
- console.log("about to parse");
- form.parse(request, function(error, fields, files) {
- console.log("parsing done");
- fs.renameSync(files.upload.path, "/tmp/test.png");
- response.writeHead(200, {"Content-Type": "text/html"});
- response.write("received image:<br/>");
- response.write("<img src='/show' />");
- response.end();
- });
- }
- function show(response) {
- console.log("Request handler 'show' was called.");
- fs.readFile("/tmp/test.png", "binary", function(error, file) {
- if(error) {
- response.writeHead(500, {"Content-Type": "text/plain"});
- response.write(error + "\n");
- response.end();
- } else {
- response.writeHead(200, {"Content-Type": "image/png"});
- response.write(file, "binary");
- response.end();
- }
- });
- }
- exports.start = start;
- exports.upload = upload;
- exports.show = show;
- var querystring = require("querystring"),
server.js
- var http = require("http");
- var url = require("url");
- function start(route, handle) {
- function onRequest(request, response) {
- var pathname = url.parse(request.url).pathname;
- console.log("Request for " + pathname + " received.");
- route(handle, pathname, response, request);
- }
- http.createServer(onRequest).listen(8888);
- console.log("Server has started.");
- }
- exports.start = start;
- var http = require("http");
fs模块的问题 文件路径问题
- function upload(response,request) {
- console.log("Request handler 'upload' was called");
- // response.writeHead(200, {
- // "Content-Type": "text/plain"
- // });
- // response.write("you are sent: " + querystring.parse(postData).text);
- // response.end();
- // response.write("hello upload");
- //return "hello upload";
- //
- //文件上传
- var form =new formidable.IncomingForm();
- console.log("start to parse");
- form.uploadDir = "tem";
- form.parse(request,function(error,fields,files){
- console.log("parsing done");
- try{
- fs.renameSync(files.upload.path,form.uploadDir+"/test.png");//主要修改了这个地方
- }catch(e){
- console.log(e);
- }
- response.writeHead(200,{"Content-Type":"text/html"});
- response.write("received image:<br/>");
- response.write("<img src='/show'>");
- response.end();
- })
- }
完全基于node的web应用的更多相关文章
- 转:基于node的web开发框架Express入门
JavaScript 标准参考教程(alpha) 草稿二:Node.js Express框架 GitHub TOP Express框架 来自<JavaScript 标准参考教程(alpha)&g ...
- 基于Node的Web聊天室
1 项目名称 Web聊天室(<这是NodeJs实战>第二章的一个案例,把整个开发过程记录下来)
- 基于 Node.js 平台,快速、开放、极简的 web 开发框架。
资料地址:http://www.expressjs.com.cn/ Express 基于 Node.js 平台,快速.开放.极简的 web 开发框架. $ npm install express -- ...
- Fenix – 基于 Node.js 的桌面静态 Web 服务器
Fenix 是一个提供给开发人员使用的简单的桌面静态 Web 服务器,基于 Node.js 开发.您可以同时在上面运行任意数量的项目,特别适合前端开发人员使用. 您可以通过免费的 Node.js 控制 ...
- KoaHub.js是基于 Koa.js 平台的 Node.js web 快速开发框架
koahubjs KoaHub.js -- 基于 Koa.js 平台的 Node.js web 快速开发框架.可以直接在项目里使用 ES6/7(Generator Function, Class, A ...
- 基于 Koa.js 平台的 Node.js web 快速开发框架KoaHub.js demo 可安装
KoaHub.js demo KoaHub.js KoaHub.js -- 基于 Koa.js 平台的 Node.js web 快速开发框架.可以直接在项目里使用 ES6/7(Generator Fu ...
- KoaHub.js -- 基于 Koa.js 平台的 Node.js web 快速开发框架之koahub-yilianyun
koahub-yilianyun 微信易联云打印机接口 koahub-yilianyun易联云打印机node接口 Installation $ npm install koahub-yilianyun ...
- koa : Express出品的下一代基于Node.js的web框架
https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001434501579966a ...
- 认识Web前端、Web后端、桌面app和移动app新开发模式 - 基于Node.js环境和VS Code工具
认识Web.桌面和移动app新开发模式 - 基于Node.js环境和VS Code工具 一.开发环境的搭建(基于win10) 1.安装node.js和npm 到node.js官网下载安装包(包含npm ...
随机推荐
- 5.2 spring5源码--spring AOP源码分析二--切面的配置方式
目标: 1. 什么是AOP, 什么是AspectJ 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP及其使用 详见博 ...
- Elasticsearch 之 Filter 与 Query 有啥不同?
今天来了解下 Elasticsearch(以下简称 ES) 中的 Query 和 Filter. 在 ES 中,提供了 Query 和 Filter 两种搜索: Query Context:会对搜索进 ...
- Ubuntu18.04系统设置为中文语言
1.选择右上角设置按钮 2.管理已安装的语言 3.安装简体中文 安装好后是这样的 会发现汉语中文那一块是灰色的,怎么点都点不亮 4.拖拽 汉语(中国) 到最顶边 然后应用 5.重启 然后就出现这个画面 ...
- 一文弄懂-《Scalable IO In Java》
目录 一. <Scalable IO In Java> 是什么? 二. IO架构的演变历程 1. Classic Service Designs 经典服务模型 2. Event-drive ...
- HDU 1565 方格取数 状压dp
题目: 给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大. Input 包括多 ...
- P1439 【模板】最长公共子序列(DP)
题目描述 给出1-n的两个排列P1和P2,求它们的最长公共子序列. 输入输出格式 输入格式: 第一行是一个数n, 接下来两行,每行为n个数,为自然数1-n的一个排列. 输出格式: 一个数,即最长公共子 ...
- NCD 2019 M. NCD Salary
题意 :给你两个指数类型的数\(A^m\)和\(B^n\),比较他们的大小.保证底数和指数中最多只有一个为0. 题解 :题目数据非常大,肯定不能直接比较.由换底公式和\(Log\)函数的性质我们知道: ...
- 洛谷 P4017 最大食物链计数 (拓扑排序,思维)
题意:有\(n\)个点,连\(m\)条边,求最多有多少条食物链(从头走到为有多少条路径). 题解:之前抽了点时间把拓扑排序补完了,这题其实就是一道拓扑排序的裸题.关于拓扑排序: 1.首先,我们用\ ...
- Codeforces Round #669 (Div. 2) B. Big Vova (枚举)
题意:有一个长度为\(n\)的序列,你需要对其重新排序,构造一个新数组\(c\),\(c_{i}=gcd(a_{1},...,a{i})\)并且使得\(c\)的字典序最小. 题解:直接跑\(n\)次, ...
- vs2017创建文件模板(自动添加创建信息:创建者,创建日期等信息)
很多小伙伴在创建新的类的时候都要都要手动写类的注释,如作者名称.创建日期.版本等等,当有几个类的时候还可以手动写写,但有几十个或者更多的类的时候就麻烦了,所以我们可以设定Visual Studio 2 ...