ssh2-sftp-client实现前端项目自动部署

目录

自动部署完整代码 

package.json

 deploy /config   服务器信息

 deploy / index  部署命令入口文件

 如果需要在服务器执行命令

shelljs的使用说明

shelljs的安装

shelljs的使用说明

重要方法介绍

exec()

 ls()

ShellString()

ShellString.prototype.to(file)

ShellString.prototype.toEnd(file)

SSH2-SFTP-Client 使用文档

安装

使用方法

new SftpClient(name) ===> SFTP client object

connect(config) ===> SFTP object 

downloadDir(srcDir, dstDir, options) ==> string

rmdir(path, recursive) ==> string 

uploadDir(srcDir, dstDir, options) ==> string 

node js --- fs模块

.mkdir 创建文件夹 

 __dirname

path.resolve()用法 

process

1. 了解process.argv

 2. process对象的用途

3. 结论

chalk开源库

前言

chalk作用与使用

chalk在node中使用的版本坑

chalk在node中使用场景


自动部署完整代码 

package.json

下载这三个包

  • shelljs :执行 shell命令
  • ssh2-sftp-client 与服务器建立链接(内部有ssh2)
  • chalk 打印彩色输出
  "devDependencies": {
    "shelljs": "^0.8.5",
    "ssh2-sftp-client": "^9.1.0",
    "chalk": "4.1.0"
  },

配置脚本命令  deploy 注意后边加上运行环境
执行deploy命令时内部执行了打包动作

  "scripts": {
    "dev": "vue-cli-service serve",
    "staging": "vue-cli-service serve --mode staging",
    "build:prod": "vue-cli-service build",
    "build:stage": "vue-cli-service build --mode staging",
    "preview": "node build/index.js --preview",
    "lint": "eslint --ext .js,.vue src",
    "deploy": "node deploy/index.js --prod"
  },

 deploy /config   服务器信息

module.exports = [
  {
    id: 0,
    nodeEnv: "prod",
    name: "正式环境",
    domain: "",
    host: "ip",
    port: 端口,
    username: "用户名",
    password: "密码",
    path: "/data/www/paccount",//部署路径
    removepath: "/data/www/paccount", //删除路径
  },
];

 deploy / index  部署命令入口文件

// 服务器配置文件
const config = require("./config.js");
// shell命令
const shell = require("shelljs");
// 输出颜色
const chalk = require("chalk");
// node fs 模块 读写文件
const fs = require("fs");
// node path模块 获取文件路径
const path = require("path");
// SSH2-SFTP-Client 是一个用于在Node.js中进行SSH SFTP操作的强大工具。它允许你建立SSH连接并进行文件传输,非常适用于自动化任务和远程文件管理。本文将引导你如何安装、配置和使用SSH2-SFTP-Client。
const Client = require("ssh2-sftp-client");
// 获取环境变量
const rawArgv = process.argv.slice(2);
// 日期插件
const dayjs = require("dayjs");

//判断环境
const filterStage = rawArgv.includes("--prod") ? "prod" : "stage";
console.log(chalk.blue("当前环境:", filterStage));

// 打包
const compileDist = async () => {
  // 根据环境执行打包命令
  if (shell.exec(`npm run build:${filterStage}`).code === 0) {
    console.log(chalk.green("打包成功"));
  }
};
// 部署
async function connectShell(params) {
  // 判断需要上传的服务器
  config
    .filter((item) => item.nodeEnv == filterStage)
    .map((item, index) => {
      const sftp = new Client();
      sftp
        .connect({
          host: item.host,
          port: item.port,
          username: item.username,
          password: item.password,
        })
        // 备份
        .then(() => {
          if (index > 0) {
            return "ok";
          }
          console.log(
            chalk.red(`${item.host}--`) + chalk.blue(`---执行下拉文件备份---`)
          );
          console.log(chalk.blue(`---创建备份文件夹中···---`));
          let newFile = `/${item.host}/${dayjs().format(
            "YYYY-MM-DD"
          )}/dist-${dayjs().format("HH_mm_ss")}`;
          // 创建本地文件夹
          fs.mkdir(
            path.resolve(__dirname, `../distbak${newFile}`),
            { recursive: true },
            (err) => {
              if (err) throw err;
              console.log(chalk.green("---创建备份文件夹成功---"));
            }
          );
          //执行服务器下拉操作
          return sftp.downloadDir(
            item.path, //服务器路径
            path.resolve(__dirname, `../distbak${newFile}`) //写入的本地路径地址
          );
        })
        // 删除
        .then(() => {
          if (index === 0) {
            console.log(
              chalk.red(`${item.host}--`) + chalk.blue(`---备份完成---`)
            );
          }
          console.log(
            chalk.yellow(`${item.host}--`) +
              chalk.red(`---执行删除文件中···---`)
          );
          // 删除路径 递归删除
          return sftp.rmdir(item.path, true);
        })
        // 上传
        .then(() => {
          console.log(
            chalk.red(`${item.host}--`) + chalk.green(`执行删除文件成功---`)
          );
          console.log(
            chalk.hex("#DEADED").bold(`---${item.host}执行上传文件中···---`)
          );
          return sftp.uploadDir(path.resolve(__dirname, "../dist"), item.path);
        })
        // 上传成功 关闭链接
        .then(() => {
          console.log(
            chalk.yellow(`${item.host}--`) + chalk.green(`上传完成,部署成功---`)
          );
          sftp.end();
        })
        // 上传失败
        .catch((err) => {
          console.error(
            err,
            chalk.red(`${item.host}--`) + chalk.red(`上传失败`)
          );
          sftp.end();
        });
    });
}

async function runStart() {
  await compileDist();
  await connectShell();
}
runStart();

 如果需要在服务器执行命令

在部署完成后执行

SSH2是一个用于在网络上安全地访问远程计算机的协议,而上述代码段则使用Node.js的ssh2库来执行SSH连接和操作。这段代码中包含了两个事件处理器:

  1. .on("ready", function () { ... })

    • 这是ssh2库中的一个事件处理器,它在SSH连接准备就绪时触发。当与远程主机建立SSH连接后,会执行其中的代码块。通常,你可以在这个事件中执行需要在SSH连接建立后执行的操作。
  2. .connect({ ... })

    • 这是用于建立SSH连接的方法,其中包含了一个包含连接参数的对象,如主机地址、端口、用户名和密码等。在调用.connect()时,ssh2库将尝试连接到指定的远程主机。

在代码中,当SSH连接准备就绪("ready")时,它执行了一个命令,使用conn.exec()执行chmod命令,将目标目录的权限设置为755(允许读、写和执行)。如果设置权限成功,它会打印一条成功消息,并结束SSH连接。

总之,上述代码段通过ssh2库建立SSH连接,并在连接就绪后执行特定的命令来更改目标目录的权限。这通常用于在远程服务器上执行操作,例如修改文件权限。

const ClientOrg = require("ssh2").Client;
async function chmodDir(item) {
  if (!item) {
    throw "获取ip配置失败";
  }

  const conn = new ClientOrg();
  conn
    .on("ready", function () {
      conn.exec("chmod  755  /etc/nginx/html -R", function (err, stream) {
        if (err) throw err;
        console.log(
          chalk.red(`${item.host}--`) + chalk.green(`---添加目录权限成功---`),
        );
        conn.end();
      });
    })
    .connect({
      host: item.host,
      port: item.port,
      username: item.username,
      password: item.password,
    });
}

shelljs的使用说明
 

shelljs模块重新包装了child_process,调用系统命令更加简单。
shelljsUnix ShellNode.js API层的轻量级实现,可以支持Windows、Linux、OS X。你可以像

<think>好的,用户想在webssh-1.6.2版本中新增一个页面实现SFTP上传和下载功能。我需要先回顾之前的回答,看看有没有需要调整的地方。用户还提供了几个引用,不过看起来主要是关于FileZilla、curl和zlib的内容,可能需要结合这些信息。 首先,用户之前的问题是关于在Python WebSSH项目添加SFTP功能,现在具体到webssh 1.6.2版本,可能需要考虑该版本的具体结构和依赖。需要确认webssh 1.6.2是否已经使用了Paramiko库,因为Paramiko支持SFTP。之前的回答已经提到了使用Paramiko的SFTP模块,所以可能需要沿用这个方法。 用户提供的引用[1]提到使用FileZilla配置SFTP连接,这可能涉及到如何设置SFTP客户端,但用户现在需要的是在Web界面中集成,所以可能需要前端的上传下载组件。引用[2]和[3]关于curl的使用,可能对后端处理文件传输有帮助,比如分块上传或处理大文件。引用[4]提到的zlib库可能与压缩有关,但用户的需求是上传下载,可能暂时不需要压缩功能,但可以注意是否有相关需求。 接下来,我需要根据用户当前的请求,调整之前的步骤以适应webssh 1.6.2的结构。可能需要检查webssh的现有代码,比如SSH连接管理部分,如何扩展SFTP功能。同时,前端部分需要新增页面,比如sftp.html,以及处理文件列表、上传下载的JavaScript代码。 另外,用户提到的是webssh-1.6.2版本,可能需要确认其使用的框架,比如是否基于Flask,或者是否有其他路由和处理方式。之前的示例中使用的是Flask的路由,但需要适配到实际项目中。 安全方面,需要确保路径检查,防止用户访问超出其权限的目录,这可能需要类似secure_path的函数来限制路径。同时,处理大文件时需要考虑内存问题,使用流式传输而不是一次性读取,这在之前的代码示例中已经用分块读取处理了。 用户可能还需要处理会话管理,因为WebSSH可能每个用户有一个SSH连接,需要确保SFTP会话与之关联,避免混用。可能需要修改现有的SSHManager类,添加sftp属性,并在需要时打开SFTP通道。 最后,部署时可能需要调整Web服务器的配置,比如Nginx的上传大小限制,这在之前的回答中已经提到,需要再次确认是否适用于当前版本。 现在需要将这些步骤具体化,结合用户提供的引用,但可能引用中的内容更多是参考,实际需要以用户的实际需求为主。需要确保代码兼容webssh 1.6.2的结构,可能需要查看该版本的源码结构,比如路由定义、模板位置等,确保新增的页面和接口正确集成。</think>基于webssh-1.6.2版本添加SFTP文件传输功能,需结合项目架构进行如下改造: ### 一、后端改造(基于Paramiko扩展) 1. **增强SSHClient类** 在`app/ssh.py`中扩展SFTP功能: ```python class SSHClient: def __init__(self): self.ssh = paramiko.SSHClient() self.sftp = None # 新增SFTP客户端 def open_sftp(self): if not self.sftp or self.sftp.sock.closed: self.sftp = self.ssh.open_sftp() return self.sftp # 返回激活的SFTP通道[^1] ``` 2. **新增路由处理** 在`app/routes.py`中添加: ```python from werkzeug.utils import secure_filename @app.route('/sftp', methods=['POST']) def sftp_operation(): session = get_ssh_session(request.form['id']) # 复用现有SSH会话管理 operation = request.form['operation'] if operation == 'list': path = secure_path(request.form.get('path', '/')) sftp = session.open_sftp() return jsonify([{ 'name': f.filename, 'type': 'directory' if S_ISDIR(f.st_mode) else 'file' } for f in sftp.listdir_attr(path)]) ``` ### 二、前端实现 1. **新建sftp.html模板** 在`templates/`目录下创建: ```html <div class="file-manager"> <div class="path-bar">{{ current_path }}</div> <table class="file-table"> <tr v-for="item in files" @dblclick="handleDblClick(item)"> <td><i :class="item.type === 'directory' ? 'folder-icon' : 'file-icon'"></i></td> <td>{{ item.name }}</td> </tr> </table> <input type="file" webkitdirectory multiple @change="handleUpload"> </div> ``` 2. **实现分块上传** 结合引用[2][^2]的curl分块传输思路: ```javascript function chunkedUpload(file, remotePath) { const chunkSize = 5 * 1024 * 1024; // 5MB分块 let offset = 0; const uploadNext = () => { const chunk = file.slice(offset, offset + chunkSize); const formData = new FormData(); formData.append('chunk', chunk); formData.append('offset', offset); formData.append('total', file.size); fetch(`/sftp/upload?path=${encodeURIComponent(remotePath)}`, { method: 'POST', body: formData }).then(res => { if (offset + chunkSize < file.size) { offset += chunkSize; uploadNext(); } }); }; uploadNext(); } ``` ### 三、安全增强 1. **路径校验** 参考FileZilla的路径管理逻辑[^1]: ```python def validate_sftp_path(user, path): # 限制用户只能访问/home/[用户名]目录 allowed_base = os.path.join('/home', user) normalized = os.path.abspath(os.path.join(allowed_base, path.lstrip('/'))) if not normalized.startswith(allowed_base): raise SecurityError("非法路径访问") return normalized ``` 2. **传输加密** 复用现有SSH连接的加密通道: ```python @app.route('/sftp/download') def download_file(): path = validate_sftp_path(current_user, request.args['path']) sftp = get_current_sftp() def generate(): with sftp.file(path, 'rb') as f: while True: data = f.read(4096) if not data: break yield data return Response(generate(), headers={ 'Content-Type': 'application/octet-stream', 'Content-Disposition': f'attachment; filename="{os.path.basename(path)}"' }) ``` ### 四、项目结构变更 ``` webssh/ ├── app/ │ ├── sftp_handlers.py # 新增SFTP业务逻辑 │ └── security.py # 路径校验模块[^1] ├── static/ │ └── sftp.js # 前端交互逻辑 └── templates/ └── sftp.html # SFTP操作界面 ``` --相关问题--: 1. 如何实现WebSFTP的目录权限控制? 2. 怎样处理文件名包含特殊字符的情况? 3. 如何实现服务端的并发文件传输管理? 4. Web界面如何显示实时传输进度条?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端 贾公子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值