代码:
const http = require('http');
const qs = require('qs');
const fs = require('fs');
const Url = require('url');
const path = require('path');
const toJSON = (obj) => {
return JSON.stringify(obj);
}
const equal = (str1, str2) => {
return (isString(str1) && isString(str2)) ?
str1.toLowerCase() === str2.toLowerCase() :
str1 === str2;
}
const isString = (str) => {
return typeof str === 'string';
}
const isObject = (o) => {
return typeof o === 'object';
}
const isFunction = (fn) => {
return (fn &&
[
"[object Function]",
"[object AsyncFunction]"
].indexOf(Object.prototype.toString.call(fn)) > -1);
}
const isRegexp = (reg) => {
return Object.prototype.toString.call(reg) === "[object RegExp]";
}
const formatReq = (req, obj = false) => {
try {
return Url.parse(req.headers.host + req.url, obj);
} catch(error) {
return null;
}
}
const GET = 'GET',
POST = 'POST',
TYPE_FILE = 'file';
const check = ( source , target) => {
let type = Object.prototype.toString.call(target);
type = type.split(' ')[1].replace(']', '');
const Build = {
RegExp: () => {
return new RegExp(target).test(source);
},
String: () => {
return source === target;
},
Function: () => {
return target(source);
}
}
return Build[type] ? Build[type]() : false;
}
class Queue {
constructor() {
this.data = [];
}
set(item) {
const d = this.find({url: item.url, type: item.type});
if( d && d.length > 0 ) {
d[0].cb.concat(item.cb);
}else {
this.push(item);
}
return this.data;
}
get(o) {
this.data.find((item) => item === o);
}
push(item) {
this.data.push(item);
}
findByUrl(url) {
return this.data.filter((item) => url === item.url);
}
findByMethod(method) {
return this.data.reduce((item, pre) => {
if(equal(item.method, method)){
pre.push(item);
}
return pre;
}, []);
}
find(findObj) {
let result = [...(this.data || [])];
Object.keys(findObj).map((key) => {
result = result.filter((item) => {
return (item[key] && check(findObj[key], item[key]))
});
});
return result;
}
}
class Trunsfer {
constructor(req, res) {
this.request = req;
this.response = res;
}
get req() {
const { request } = this;
return Object.assign(this.request, {
get query() {
return formatReq(request, true).query;
},
get body() {
if( equal(request.method, GET) ) {
return this.query;
} else {
return async() => {
return new Promise(( resolve ) => {
let data = [];
request.on('data', (chunk) => {
data.push(chunk);
})
request.on('end', () => {
resolve( Buffer.concat(data) );
});
});
}
}
},
get parse() {
return Url.parse;
}
})
}
get res() {
const { response } = this;
return Object.assign(response, {
send(...args) {
response.end(...args);
},
get parse() {
return Url.parse;
}
});
}
}
class Http {
constructor() {
this.Server = http.createServer(this.callback.bind(this));
this.Queue = new Queue();
}
notFond(res) {
res.writeHead(404,{'Content-Type' : 'text/html;charset=utf-8'});
res.end('404');
}
run(cb, ...args) {
cb.map((callback) => {
if (isFunction(callback)) {
callback(...args);
}
})
}
async callback(request, response) {
const { req, res } = new Trunsfer(request, response);
const reqObj = formatReq(req);
const app = this.Queue.find({ method: req.method, url: reqObj.pathname});
if ( app && app.length > 0 ) {
app.map(async (item) => {
if ( item.type && item.type === TYPE_FILE ) {
await this.readFile(path.resolve(item.root || './', '.' + reqObj.pathname)).then((data) => {
this.run(item.cb, req, res, data);
})
.catch((err) => {
console.log(err);
});
return;
}
this.run(item.cb, req, res);
})
} else {
this.notFond(res);
}
}
request(options, callback) {
const op = isString(options) ? {
url: options
}: Object.assign({}, options);
if (isFunction(callback)) {
op.cb = [callback];
}
this.Queue.set(op);
}
get(options, callback) {
const op = isString(options) ? {
url: options,
method: GET
}: Object.assign({ method: GET }, options);
this.request(op, callback);
}
post(options, callback) {
const op = isString(options) ? {
url: options,
method: POST
}: Object.assign({ method: POST }, options);
this.request(op, callback);
}
readFile(...args) {
return new Promise((resolve) => {
const rs = fs.createReadStream(...args);
let data = '';
rs.on('data', (chunk) => {
data += chunk.toString();
});
rs.on('error', (err) => {
console.log(err);
});
rs.on('end', () => {
resolve(data);
})
});
}
listen(...options) {
this.Server.listen(...options);
}
}
module.exports = Http;
使用代码:
const Http = require('./http');
const qs = require('qs');
const app = new Http();
const sleep = delay => new Promise(resolve => setTimeout(() => resolve(), delay));
// get请求
app.get('/api', async (req, res) => {
res.writeHead(200, {'Content-Type' : 'text/html;charset=utf-8'});
console.log('get: data:', req.body);
// await sleep(2000);
res.send('哈哈GET');
});
//post请求
app.post('/api', async (req, res) => {
const data = await req.body()
res.writeHead(200, {'Content-Type' : 'text/html;charset=utf-8'});
res.send(data);
});
// jsonp请求
app.get('/jsonp', async (req, res) => {
const query = req.body;
res.send(query.callback + `(${JSON.stringify({name: 1111})})`)
})
// 通过正则匹配加载
app.get({
type: 'file',
root: './',
url: /(.*)\.(css|html|img|jpg|js)$/g,
}, async (req, res, data) => {
res.writeHead(200,{'Content-Type' : 'text/html;charset=utf-8'});
res.send(data);
});
app.listen(4000);