需求: 建立一个能够上传图片的web应用。用户能够浏览应用,有一个文件上传的表单。选择图片上传,上传完成以后能够预览图片。上传的图片信息须要入库(mysql)。
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\r\n\r\n'); }); // 当前服务监听的端口 server.listen(8888); console.log("Server has started.");
涉及到的api:
http.createServer
res.writeHead
res.endhtml
当咱们在编写node服务的时候,若是服务器有异常,那node服务就直接挂掉了。那如何保证咱们的node服务不会关闭,而且会自动重启呢?
或者是咱们修改了代码,如何实现修改的代码直接生效而不用从新手动重启node服务呢?node
npm install -g nodemon
在生产环境我通常使用pm2来管理node服务。mysql
刚才咱们定义了一个简单的http服务。其中http是一个内置的模块。那其实咱们的服务都会有一个入口文件,在这里咱们定义为index.js。那咱们如何像引用http内置模块同样,在index.js里使用server.js呢?web
exports 与 module.exports 的区别:
exports是module.exports的简写。若是修改了exports的引用,也就是从新给exports赋值,则exports只是在当前文件级做用域内可用,而且exports的修改不会影响到module.exports的值。
server.jssql
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\r\n\r\n'); }); server.listen(8888); console.log("Server has started."); } // 经过给exports添加【属性值】的方式导出方法 // 或者经过给module.exports添加属性值 exports.start = start;
index.jsnpm
const server = require('./server'); server.start();
node index.js
咱们知道,访问一个web网站会有不一样的页面或者会调用不一样的接口,那这些就对应这不一样的请求路径,同时这些请求还会对应不一样的请求方法(GET, POST等)。那node如何针对这些不一样的请求路径去匹配对应的处理函数呢?api
为了处理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\r\n\r\n'); }); 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);
咱们显示一个文本区(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 = '<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>'; 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 = '<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">'+ '<input type="submit" value="Upload file" />'+ '</form>'+ '</body>'+ '</html>'; 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 + "\n"); 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:<br/>"); res.write("<img src='/show' />"); 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:<br/>"); res.write("<img src='/show' />"); res.end(); }); }
待续: