代码上传你的服务器(纯node环境完成)

简介:

目前很多公司,都不是在本地开发自己代码,或者本地开发完代码后需要把build后的文件上传给远程服务器。然后进行dev环境的测试。

当然,现在有很多种方法,很多种语言或方法都可以上传代码服务器,通常简便的方法就是使用python3,但是这样需要安装python,以及安装各种插件,通常在安装的过程中并不是很安逸,都有各种报错,或者网络超时(可以切换源解决)

这次我带来的方法是使用纯血node环境 上传代码到服务器,不需要安装任何插件。只需要两个js脚本,即可完成选择本地文件夹,上传服务器的任意文件夹路径下。

好的,准备上传你的优秀代码吧,少年!!

服务端代码:

Server.js

js 复制代码
const http = require('http');
const fs = require('fs');
const path = require('path');

const UPLOAD_DIRECTORY = path.join(__dirname, 'uploads');
if (!fs.existsSync(UPLOAD_DIRECTORY)) {
    fs.mkdirSync(UPLOAD_DIRECTORY, { recursive: true });
}

const server = http.createServer((req, res) => {
    if (req.method.toLowerCase() === 'post' && req.url === '/upload') {
        const boundary = req.headers['content-type'].split('; ')[1].replace('boundary=', '');
        let rawData = Buffer.alloc(0);

        req.on('data', (chunk) => {
                rawData = Buffer.concat([rawData, chunk]);
        });

        req.on('end', () => {
                 const rawString = rawData.toString('binary');
            const parts = rawString.split('--' + boundary).filter(part => part.trim() !== '');
            let fileData = null;
            let fileName = null;
            let targetPath = '/';

            parts.forEach(part => {
                if (part.indexOf('Content-Disposition: form-data; name="file"; filename="') !== -1) {
                    const match = part.match(/filename="(.+)"/);
                    fileName = match && match[1];
                    const fileContentIndex = part.indexOf('\r\n\r\n') + 4;
                    fileData = Buffer.from(part.substring(fileContentIndex, part.length - 2), 'binary');
                } else if (part.indexOf('Content-Disposition: form-data; name="to"') !== -1) {
                    const toIndex = part.indexOf('\r\n\r\n') + 4;
                    targetPath = part.substring(toIndex, part.length - 2).trim();
                }
            });

            if (!fileName || !fileData) {
                res.writeHead(400, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ error: 'Invalid file upload' }));
                return;
            }

            const uploadDir =  targetPath;
            if (!fs.existsSync(uploadDir)) {
                fs.mkdirSync(uploadDir, { recursive: true });
            }

            const uploadPath = path.join(uploadDir, fileName);
            const fileStream = fs.createWriteStream(uploadPath);
            fs.writeFile(uploadPath, fileData, (err) => {
                if (err) {
                    res.writeHead(500, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({ error: 'Error saving file' }));
                    return;
                }

                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({
                    message: 'File uploaded successfully',
                    path: uploadPath
                }));
            });
         });
    } else {
        res.writeHead(405, { 'Content-Type': 'text/html' });
        res.end('<html><head><title>405 Not Allowed</title></head><body><h1>405 Not Allowed</h1></body></html>');
    }
});

const PORT = 8500;
server.listen(PORT, () => {
    console.log(`Server is running on http://localhost:${PORT}`);
});

客户端代码

push.js

js 复制代码
const fs = require('fs');
const path = require('path');
const http = require('http');

// 从命令行参数获取文件路径和目标路径
const directoryPath = process.argv[2];  // 第一个命令行参数:本地目录路径
const targetPath = process.argv[3];  // 第二个命令行参数:目标上传路径
// 检查命令行参数是否存在
if (!directoryPath || !targetPath) {
    console.error('Usage: node upload.js <directoryPath> <targetPath>');
    process.exit(1);
}

// 递归遍历目录并上传文件的函数
const uploadDirectory = (dir, baseDir) => {
    // 读取目录中的文件和子目录
    fs.readdir(dir, (err, files) => {
        if (err) {
            console.error(`Error reading directory: ${dir}`, err);
            return;
        }

        files.forEach(file => {
            console.log("file",file);
            const filePath = path.join(dir, file);
            fs.stat(filePath, (err, stats) => {
                if (err) {
                    console.error(`Error getting stats for file: ${filePath}`, err);
                    return;
                }

                if (stats.isDirectory()) {
                    // 如果是目录,递归调用
                    uploadDirectory(filePath, baseDir);
                } else {
                    // 如果是文件,上传文件
                    uploadFile(filePath, baseDir+'/'+dir+'/');
                }
            });
        });
    });
};

// 上传单个文件的函数
const uploadFile = (filePath, relativePath) => {
    // 准备 HTTP 请求选项
    const options = {
        hostname: '自己的服务器ip',
        // port: ,
        path: '/upload',
        method: 'POST',
        headers: {
            'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
        }
    };

    const req = http.request(options, (res) => {
        let data = '';
        res.on('data', (chunk) => {
            data += chunk;
        });
        res.on('end', () => {
            console.log(`Uploaded: ${filePath} -> ${data}`);
        });
    });

    // 处理请求错误
    req.on('error', (error) => {
        console.error(`Error uploading file: ${filePath}`, error);
    });

    // 创建 multipart/form-data 内容
    const boundary = '----WebKitFormBoundary7MA4YWxkTrZu0gW';
    const fileName = path.basename(filePath);
    const fileStream = fs.createReadStream(filePath);

    req.write(`--${boundary}\r\n`);
    req.write(`Content-Disposition: form-data; name="file"; filename="${fileName}"\r\n`);
    req.write(`Content-Type: application/octet-stream\r\n\r\n`);

    fileStream.pipe(req, { end: false });

    fileStream.on('end', () => {
        req.write(`\r\n--${boundary}\r\n`);
        req.write(`Content-Disposition: form-data; name="to"\r\n\r\n`);
        req.write(`${relativePath}\r\n`); // 目标地址
        req.write(`--${boundary}--\r\n`);
        req.end();
    });
};

// 开始递归遍历和上传
uploadDirectory(directoryPath, targetPath);

nginx配置

js 复制代码
http {
  ...
  client_max_body_size 100M; # 文件大小限制
}
server {
  	location /upload {
                proxy_pass http://127.0.0.1:8500;  # 代理到你的 Node.js 服务器
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;

                # 允许 POST 请求
                if ($request_method !~ ^(GET|POST)$ ) {
                        return 405;
                }
        }
}

上传命令:

  1. 使用pm2 start Server.js 启动服务端服务 (可以直接使用node启动,推荐pm2)
  2. 本地服务node push.js <要推送的文件地址> <目标地址> 例如: node push.js test-push/ workSpace/ [注]:有没有 / 都可以
  3. 注意文件位置!!
相关推荐
奕辰杰15 分钟前
关于npm前端项目编译时栈溢出 Maximum call stack size exceeded的处理方案
前端·npm·node.js
yzzzzzzzzzzzzzzzzz11 小时前
node.js之Koa框架
node.js
Java陈序员12 小时前
轻松设计 Logo!一款 Pornhub 风格的 Logo 在线生成器!
vue.js·node.js·vite
gongzemin14 小时前
使用Node.js开发微信第三方平台后台
微信小程序·node.js·express
JavaDog程序狗19 小时前
【软件环境】Windows安装NVM
前端·node.js
自学也学好编程20 小时前
【工具】NVM完全指南:Node.js版本管理工具的安装与使用详解
node.js
Moment20 小时前
调试代码,是每个前端逃不过的必修课 😏😏😏
前端·javascript·node.js
萌萌哒草头将军1 天前
Prisma ORM 又双叒叕发布新版本了!🚀🚀🚀
前端·javascript·node.js
zyfts1 天前
手把手教学Nestjs对excel的增删改查
前端·node.js
星空下的曙光2 天前
nodejs项目中常用的npm包及分类
node.js