1.目录结构
config:配置文件,这里我们写了两套配置 开发环境和生产环境,其中index.js为配置文件入口,根据不同的环境返回不同的配置 config/index.js
const process=require('process');//当前程序信息
let mode=(process.env.OS=='Windows_NT'?'dev':'prod');//当前环境
module.exports={
mode,
...(mode=='dev'?require('./config.dev'):require('./config.prod'))
};
在server.js引用并打印
const config = require('./config')
console.log(config)
{
mode: 'dev',
DB_HOST: 'localhost',
DB_PORT: 3306,
DB_USER: 'root',
DB_PASS: '',
DB_NAME: '20181101',
HTTP_PORT: 8080,
HTTP_ROOT: 'C:\\Users\\21974\\Desktop\\nodejs\\manager\\static',
HTTP_UPLOAD: 'C:\\Users\\21974\\Desktop\\nodejs\\manager\\static\\upload'
}
libs分离出来的模块如数据库,请求等 static存放静态文件
2.测试数据库连接 引入mysql,co-mysql模块 cnpm i mysql cnpm i co-mysql 在libs/database.js
const mysql = require('mysql')
const co = require('co-mysql')
const {DB_HOST,DB_PORT,DB_USER,DB_PASS,DB_NAME} = require('../config')
let conn = mysql.createPool({
host:DB_HOST,
port:DB_PORT,
user:DB_USER,
password:DB_PASS,
database:DB_NAME
})
module.exports = co(conn)
在server.js
const config = require('./config')
const db = require('./libs/database')
;(async ()=>{
let data = await db.query('select * from item_table')
console.log(data)
})()
//返回测试数据
[
RowDataPacket { id: 3, title: 'test3', price: 23, count: 1 },
RowDataPacket { id: 2, title: 'test2', price: 100, count: 2 }
]
3.初始化路由模块 在libs/router.js
//路由表
let router = {};
function addRouter(method,url,fn) {
method = method.toLowerCase();
url = url.toLowerCase();
router[method] = router[method] || {};
router[method][url] = fn;
}
function findRouter(method,url){
method = method.toLowerCase();
url = url.toLowerCase();
if(!router[method]|| !router[method][url]){
return null;
}else{
return router[method][url];
}
}
module.exports={
addRouter,findRouter
}
router对象存放路由及路由对应的方法如
{
get:{
'/a':function(){}
}
}
addRouter添加路由
findRouter找路由\
4.初始化http模块
在libs/http.js
const http = require('http');
const url = require('url');
const querystring=require('querystring');
const zlib = require('zlib');
const fs = require('fs');
const {Form} = require('multiparty');
const {HTTP_PORT,HTTP_ROOT,HTTP_UPLOAD} = require('../config')
const router = require('./router')
http.createServer((req,res)=>{
//解析数据
let {pathname,query} = url.parse(req.url)
if(req.method=='POST'){
if(req.headers['content-type'].startsWith('application/x-www-form-urlencoded')){
//普通post
let arr = []
req.on('data',buffer=>{
arr.push(buffer)
});
req.on('end',()=>{
let post = querystring.parse(Buffer.concat(arr))
});
//找路由
handle(req.method,pathname,query,post,{})
}else{
//文件post
let form = new Form({
uploadDir:HTTP_UPLOAD
});
form.parse(req)
let post = {}
let files = {}
//普通文本
form.on('file',(name,value)=>{
post[name]=value;
});
//文件
form.on('file',(name,files)=>{
files[name] =value
})
//处理异常
form.on('error',(e)=>{
console.log(e)
})
form.on('close',()=>{
//找路由
handle(req.method,pathname,query,post,files)
})
}
}else{
//找路由(GET)
handle(req.method,pathname,query,{},{})
}
async function handle(method,url,get,post,files){
let fn = router.findRouter(method,url);//该路由对应的方法
if(!fn){
//如果该路由方法不存在认为文件请求
let filepath = HTTP_ROOT+pathname;
fs.stat(filepath,(err,stat)=>{
if(err){
res.writeHeader(404);
res.write('Not Found');
res.end();
}else{
//返回文件
let rs = fs.createReadStream(filepath)
let gz = zlib.createGzip();
rs.on('error',()=>{
});
res.setHeader('content-encoding','gzip');
rs.pipe(gz).pipe(res)
}
})
}else{
//接口请求
try{
await fn(url,get,post,files)
}catch(e){
res.writeHeader(500);
res.write('Internal Server Error');
res.end();
}
}
}
}).listen(HTTP_PORT);
console.log('server start')
在浏览器输入http://127.0.0.1:3000/index.html
返回静态页面
测试接口 server.js
const db = require('./libs/database');
const http = require('./libs/http');
const {addRouter} = require('./libs/router');
//添加路由
addRouter('get','/aaa', async (res,get,post,files)=>{
res.write('aaa');
res.end();
});
浏览器输入/aaa返回aaa 到此测试完毕 开发部分接口
const db = require('./libs/database');
const http = require('./libs/http');
const {addRouter} = require('./libs/router');
//商品列表
addRouter('get','/list', async (res,get,post,files)=>{
try{
let data = await db.query(`select * from item_table`);
res.writeJson({
error:0,
data
});
}catch(e){
res.writeJson({error:1,msg:'databse error'});
}
res.end();
// res.write()
res.end();
});
//商品添加
addRouter('get','/add', async (res,get,post,files)=>{
let {title,price,count} = post;
if(!title||!price||!count){
res.writeJson({error:1,msg:'params invalid'});
res.end();
}else{
price = Number(price);
count = Number(count);
if(isNaN(price) || isNaN(count)){
res.writeJson({error:1,msg:'params invalid'});
res.end();
}else{
// db.query(`inert into item_table(title,price,count) values('${title}',${price},${count})`)sql注入风险
try{
await db.query('insert into item_table (title,price,count) values(?,?,?)',[title,price,count]);
res.writeJson({error:0,msg:'success'});
}catch(e){
res.writeJson({error:0,msg:'error'});
}
res.end();
}
}
});