简介:
目前很多公司,都不是在本地开发自己代码,或者本地开发完代码后需要把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;
}
}
}
上传命令:
- 使用pm2 start Server.js 启动服务端服务 (可以直接使用node启动,推荐pm2)
- 本地服务node push.js <要推送的文件地址> <目标地址> 例如: node push.js test-push/ workSpace/ [注]:有没有 / 都可以
- 注意文件位置!!