koa 快速保存文件的服务器

import * as Koa from "koa";
import * as fs from "fs";
import * as path from "path";


const app = new Koa();

app.use(async ctx => {
    // console.log(ctx.url);
    // console.log(ctx.method);
    // let postData = await parsePostData(ctx);
    // ctx.body = 'Hello World';
    if (isPost("/", ctx)) {
        let postData = await parsePostData(ctx);
        console.log("收到的参数postData: ", postData);
        saveFile(JSON.stringify(postData));
    }
});

//设置监听端口
app.listen(3000, () => {
    console.log("服务器开启 127.0.0.1:3000");
});

let saveFilePath = "./File";
let saveFileName = "tongguanTime.json";

/** 保存文件 
 * @param content 保存的文件内容
*/
function saveFile(content: string) {

    if (!fs.existsSync(saveFilePath)) {
        if (mkdirsSync(saveFilePath)) {
            console.log(`${saveFilePath} 创建成功`);
        }
    }

    try {
        fs.writeFileSync(path.join(saveFilePath, saveFileName), content);
        console.log("文件保存成功");
    } catch (error) {
        console.log(error);
    }

}

/** 递归创建文件夹 
 * @param dirPath 文件夹路径
*/
function mkdirsSync(dirPath) {
    if (fs.existsSync(dirPath)) {
        return true;
    } else {
        if (mkdirsSync(path.dirname(dirPath))) {
            fs.mkdirSync(dirPath);
            return true;
        }
    }
}


/** 解析 post 参数 */
function parsePostData(ctx) {
    return new Promise((resolve, reject) => {
        try {
            let postData = '';
            ctx.req.addListener('data', (data) => { // 有数据传入的时候
                postData += data;
            });
            ctx.req.on('end', () => {
                let parseData = parseQueryStr(postData);
                resolve(parseData);
            });
        } catch (e) {
            reject(e);
        }
    })
}

// 处理 string => json
function parseQueryStr(queryStr) {
    // console.log("queryStr: ",queryStr);
    let queryData = {};
    let queryStrList = queryStr.split('&');
    // console.log("queryStrList: ",queryStrList);
    for (let queryStr of queryStrList) {
        let itemList = queryStr.split('=');
        // console.log('itemList: ', itemList);
        queryData[itemList[0]] = decodeURIComponent(itemList[1]);
    }
    // console.log("queryData: ",queryData);
    return queryData;
}

/** 是否是post请求
 * @param path url路径
 * @param ctx koa2的上下文对象
 */
function isPost(path, ctx) {
    return ctx.url === path && ctx.method === 'POST';
}

主要是今天老总让我玩游戏,然后把游戏中的通关时间记录一下,但是egret不能保存文件。所以写了这个服务器用来保存文件。

egret的游戏每次通了一关,就向这个服务器发起请求,然后再把数据保存成文件。

把代码记录在博客,方便下次我复制。

使用postman 测试OK。

最后,再添加一些 安全的保存文件方法:

index.ts

import * as Koa from "koa";
import * as fs from "fs";
import * as path from "path";

const app = new Koa();

app.use(async ctx => {
    //解决 egret 请求时,跨域的问题
    ctx.set('Access-Control-Allow-Origin', '*');


    if (isPost("/", ctx)) {
        let postData = await parsePostData(ctx);
        // console.log("收到的参数postData: ", postData);
        safeSaveFile(JSON.stringify(postData));

        //一定要返回一个响应,不然egret那边会报 Uncaught Error: #1011: 流错误。
        ctx.body = "文件保存成功";
    }
});

//设置监听端口
app.listen(3000, () => {
    console.log("服务器开启 127.0.0.1:3000");
});

/** 保存的目录 */
let saveDirPath = "./File";
/** 保存的文件名 */
let saveFileName = "tongguanTime.json";
/** 保存的文件路径 */
let saveFilePath = path.join(saveDirPath, saveFileName);

/** 保存文件 
 * @param content 保存的文件内容
*/
function saveFile(content: string) {

    if (!fs.existsSync(saveDirPath)) {
        if (mkdirsSync(saveDirPath)) {
            console.log(`${saveDirPath} 创建成功`);
        }
    }

    try {
        fs.writeFileSync(saveFilePath, content);
        console.log("文件保存成功");
    } catch (error) {
        console.log(error);
    }

}

/** 安全的保存文件 如果已经存在该文件,则读取该文件的内容,然后将要保存的内容,已有的覆盖,没有的追加。如果该文件的内容不合规,则复制一份暂时保存
 * @param saveJsonStr 保存的文件内容
*/
function safeSaveFile(saveJsonStr: string) {
    let fileJsonObj = {};
    if (fs.existsSync(saveFilePath)) {
        let fileJsonStr = fs.readFileSync(saveFilePath).toString();
        try {
            fileJsonObj = JSON.parse(fileJsonStr);
        } catch (error) {
            console.log("不是json格式的内容,已重置");
            fs.copyFileSync(saveFilePath, path.join(saveDirPath, Date.now() + "_" + saveFileName))
            fileJsonObj = {};
        }

    }

    /** 要保存的json对象 */
    let saveJsonObj = JSON.parse(saveJsonStr);

    if (isNullObj(fileJsonObj)) {
        // console.log("是个空对象");
        fileJsonObj = saveJsonObj;
    } else {
        for (const key in saveJsonObj) {
            if (saveJsonObj.hasOwnProperty(key)) {

                //如果已存在的文件中,和要保存的json对象 内容一致,则记录老的值,并将新的值添加
                // if (fileJsonObj[key] != element) {
                //     fileJsonObj[key + "_old"] = fileJsonObj[key];
                // }
                fileJsonObj[key] = saveJsonObj[key];
            }
        }
    }
    //写入文件
    try {
        fs.writeFileSync(saveFilePath, JSON.stringify(fileJsonObj));
        console.log("保存的内容:", fileJsonObj);
        console.log("文件保存成功");
    } catch (error) {
        console.log(error);
    }

}

/** 判断是否是空对象 */
function isNullObj(obj) {

    for (var key in obj) {
        return false;
    }
    return true;

}

/** 递归创建文件夹 
 * @param dirPath 文件夹路径
*/
function mkdirsSync(dirPath) {
    if (fs.existsSync(dirPath)) {
        return true;
    } else {
        if (mkdirsSync(path.dirname(dirPath))) {
            fs.mkdirSync(dirPath);
            return true;
        }
    }
}


/** 解析 post 参数 */
function parsePostData(ctx) {
    return new Promise((resolve, reject) => {
        try {
            let postData = '';
            ctx.req.addListener('data', (data) => { // 有数据传入的时候
                postData += data;
            });
            ctx.req.on('end', () => {
                let parseData = parseQueryStr(postData);
                resolve(parseData);
            });
        } catch (e) {
            reject(e);
        }
    })
}

// 处理 string => json
function parseQueryStr(queryStr) {
    // console.log("queryStr: ",queryStr);
    let queryData = {};
    let queryStrList = queryStr.split('&');
    // console.log("queryStrList: ",queryStrList);
    for (let queryStr of queryStrList) {
        let itemList = queryStr.split('=');
        // console.log('itemList: ', itemList);
        queryData[itemList[0]] = decodeURIComponent(itemList[1]);
    }
    // console.log("queryData: ",queryData);
    return queryData;
}

/** 是否是post请求
 * @param path url路径
 * @param ctx koa2的上下文对象
 */
function isPost(path, ctx) {
    return ctx.url === path && ctx.method === 'POST';
}

 这是egret的客户端代码:

HttpRequestUtil.ts

/** http请求测试用 */
class HttpRequestUtil {

    /** 保存通关记录到服务器 */
    static saveTongGuanTime(jsonStr: string) {
        let url = "http://127.0.0.1:3000";
        this.startPost(url, jsonStr);
    }

    /** 开始post请求 */
    static startPost(url: string, json: string) {


        //new http请求
        const request = new egret.HttpRequest();
        // request.responseType = egret.HttpResponseType.TEXT;
        //请求参数
        // var params = "p1=postP1&p2=postP2";

        //发送post请求
        request.open(url, egret.HttpMethod.POST);

        //设置响应头
        // request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
        // request.setRequestHeader("Content-Type", "application/json;charset=utf-8");

        //发送参数
        request.send(this.jsonToPostParmameter(json));

        //监听当前请求完成后,返回数据
        request.addEventListener(egret.Event.COMPLETE, function (evt) {
            //请求返回数据
            var data = request.response;
            console.log("收到的数据: ", data);
        }, this);
    }

    /** json -> post 参数格式 
     * @param jsonStr json字符串
    */
    static jsonToPostParmameter(jsonStr: string) {
        let postParmStr = "";
        let jsonObj = JSON.parse(jsonStr);
        for (let key in jsonObj) {
            if (jsonObj.hasOwnProperty(key)) {
                let element = jsonObj[key];
                postParmStr += `${key}=${element}&`;
            }
        }
        postParmStr = postParmStr.substring(0, postParmStr.lastIndexOf('&'));
        return postParmStr;
    }
}
原文地址:https://www.cnblogs.com/dmc-nero/p/13094222.html