调用测试:
xhr=new XMLHttpRequest();xhr.open("POST","/upload",false);f=new FormData();f.append("upfile_b64",btoa("1234"));f.append("mime","xxx/txt");f.append("upfile",new Blob(["真好123"]),"xxx.txt");xhr.send(f);xhr.responseText
**/
module.exports={ Start: async function(Port, SSL){
var fs = require("fs");
var fs2 = fs.promises;
var NodePath = require("path");
var Api={};
Api.GET_=Api.GET_echo=async function(ctx,args){
ctx.setValue('<h1>LocalServer正在运行...</h1><a href="'+ctx.getUrl("/Recorder/")+'">'+ctx.getUrl("/Recorder/")+'</a><pre>'+JSON.stringify({url:ctx.getUrl(), method:ctx.req.method, headers:ctx.req.headers},null,"\t")+'</pre>','html');
};
Api.POST_=Api.POST_echo=async function(ctx,args){
ctx.setValue({url:ctx.getUrl(), method:ctx.req.method, headers:ctx.req.headers, args:args});
};
Api.POST_upload=async function(ctx,args){
var upfile=args.upfile;
if(!upfile || !upfile.data){
return ctx.error("upfile参数无效");
}
var savePath=await uploadSave(ctx,upfile.data,upfile.type||"",upfile.filename||"");
ctx.endLog=()=> console.log(" \x1B[33m上传文件\x1B[0m,"+upfile.data.length+"字节,已保存在:"+savePath+",请求参数:", args);
};
Api.POST_uploadBase64=async function(ctx,args){
var upfile_b64=args.upfile_b64||""; args.upfile_b64="<Base64 length="+upfile_b64.length+">";
var mime=args.mime||"";
var data=null;
try{
var data=Buffer.from(upfile_b64,"base64");
}catch(e){ }
if(!data || !upfile_b64){
return ctx.error("upfile_b64参数无效");
};
var savePath=await uploadSave(ctx,data,mime,"");
ctx.endLog=()=> console.log(" \x1B[33m上传文件Base64\x1B[0m,"+data.length+"字节,已保存在:"+savePath+",请求参数:", args);
};
var uploadSave=async function(ctx,data,mime,fileName){
var ext=(/\.(\w+)$/.exec(fileName.toLowerCase())||[])[1];
if(!ext){
ext=(/\/(\w+)$/.exec(mime.toLowerCase())||[])[1];
}
ext=ext||"bin";
var now=new Date();
var fileName=""+now.getFullYear()
+("0"+(now.getMonth()+1)).substr(-2)
+("0"+now.getDate()).substr(-2)
+"-"+("0"+now.getHours()).substr(-2)
+("0"+now.getMinutes()).substr(-2)
+("0"+now.getSeconds()).substr(-2)
+"-"+("00"+now.getMilliseconds()).substr(-3)
+(Math.random()+"").substr(2,6)
+"."+ext;
var savePath="./upload/"+fileName;
await fs2.mkdir("./upload", {recursive:true});
await fs2.writeFile(savePath, data);
ctx.setValue({ url:ctx.getUrl("/Recorder/assets/node-localServer/upload/"+fileName) });
return savePath;
};
Api.GET_Recorder=async function(ctx,args){
var path=/^\/Recorder\/?([^\?]*)(\?.*)?$/.exec(ctx.req.url);
if(path){
path="/"+decodeURIComponent(path[1]);
}
var root=NodePath.resolve("../../");
var scope=Api.GET_Recorder;
if(!scope.access){
try{
await fs2.access(root+"/dist/recorder-core.js");
await fs2.access(root+"/src/recorder-core.js");
scope.access=1;
}catch(e){ scope.access=-1; }
}
if(scope.access!=1){
ctx.status=500;
ctx.setValue("<h1>请在clone的Recorder目录内开启本服务器,否则不允许访问Recorder路径下的静态文件</h1>","html");
return;
}
var fullPath=NodePath.resolve(root,"."+path);
if(!path || fullPath.indexOf(root)!=0){
ctx.status=403;
ctx.setValue("<h1>路径无效</h1>","html");
return;
}
try{
if((await fs2.stat(fullPath)).isDirectory()){
if(!/\/(\?|$)/.test(ctx.req.url)){
ctx.status=404;
ctx.setValue("<h1>目录,没有编写301跳转代码</h1>","html");
return;
}
fullPath+="/index.html";
await fs2.stat(fullPath);
}
}catch(e){
ctx.status=404;
ctx.setValue("<h1>路径不存在</h1>","html");
return;
}
var ext=(/\.(\w+)$/.exec(fullPath.toLowerCase())||[])[1];
var mime=({
html:"text/html"
,css:"text/css"
,js:"application/javascript"
,txt:"text/plain"
,md:"text/plain"
,jpg:"image/jpeg"
,gif:"image/gif"
,png:"image/png"
,mp4:"video/mp4"
,webm:"video/webm"
,mp3:"audio/mp3"
,wav:"audio/wav"
,ogg:"audio/ogg"
,amr:"audio/amr"
})[ext]||"application/octet-stream";
ctx.setValue(await fs2.readFile(fullPath), mime);
};
await (async function(){
var http = require('http');
var https = require('https');
var querystring = require('querystring');
var multipart = require('parse-multipart-data');
var reqProcess=function(req, rep) {
var ctx={
req:req,rep:req
,data:{c:0,m:"",v:""}
,status:200,setCT:false,contentType:"text/json; charset=utf-8"
};
ctx.setValue=function(val,contentType){
if(contentType!=null){
ctx.setCT=true;
ctx.contentType=!contentType||contentType=="html"?"text/html; charset=utf-8":contentType;
};
ctx.data.v=val;
};
ctx.error=function(msg){
ctx.data.c=1;
ctx.data.m=msg;
return ctx;
};
ctx.isError=function(){
return ctx.data.c!=0;
};
ctx.getMsg=function(){
return ctx.data.m;
};
ctx.getUrl=function(path){
var url=SSL && SSL.certFile?"https":"http";
url+="://"+req.headers.host.replace(/:\d+/,"");
if(Port!=80 && Port!=443){
url+=":"+Port;
}
url+=path||req.url;
return url;
};
ctx.endLog=function(){};
var post = Buffer.alloc(0);
req.on('data', function(chunk){
post = Buffer.concat([post, chunk], post.length+chunk.length);
});
req.on('end', function(){
(async function(){
if(req.method!="GET" && req.method!="POST"){
ctx.setValue("Method: "+req.method, "html");
}else try{
var mp=/^multipart\/form-data.*boundary=(.*)/i.exec(req.headers["content-type"]);
if(mp){
var arr = multipart.parse(post,mp[1]);
var params = {};
for(var i=0;i<arr.length;i++){
var o=arr[i];
if(o.filename||o.type){
params[o.name]=o;
}else{
params[o.name]=o.data.toString();
}
}
}else{
var params = querystring.parse(post.toString());
}
var path0=(/^\/([^\/\?]+)/.exec(req.url)||[])[1]||"";
var fn=Api[req.method+"_"+path0]
if(fn){
await fn(ctx, params);
}else{
ctx.status=404;
ctx.error(req.method+"路径不存在:"+req.url);
};
}catch(e){
ctx.error("执行出错:"+e.stack);
};
if(!ctx.setCT){
try{
var sendData=JSON.stringify(ctx.data);
}catch(e){
sendData=JSON.stringify({c:1,m:"返回数据失败:"+e.stack});
}
}else{
var sendData=ctx.data.v;
}
rep.writeHead(ctx.status, {
'Content-Type': ctx.contentType
, 'Access-Control-Allow-Origin':'*'
});
rep.end(sendData);
console.log("["+new Date().toLocaleString()+"]:"+Port+" "+req.method+" "+ctx.status+" "+Buffer.byteLength(sendData)+" "+post.length+" "+req.url);
ctx.endLog();
})();
});
};
var UrlProtocol="http";
var UrlPort=Port==80?"":":"+Port;
if(SSL && SSL.certFile){
UrlProtocol="https";
UrlPort=Port==443?"":":"+Port;
}
console.log("正在创建"+UrlProtocol+"服务(port:"+Port+")...");
if(SSL && SSL.certFile){
https.createServer({
cert: fs.readFileSync(SSL.certFile)
,key: fs.readFileSync(SSL.keyFile)
}, reqProcess).listen(Port);
}else{
http.createServer(reqProcess).listen(Port);
}
console.log("\x1B[32m"+UrlProtocol.toUpperCase()+"服务正在运行"+"\x1B[0m"
+" \x1B[33m"+"访问URL:"+UrlProtocol+"://【127.0.0.1、局域网ip、域名】"+UrlPort+"/"+"\x1B[0m");
})();
}
};