专业编程教程与实战项目分享平台

网站首页 > 技术文章 正文

前端项目打包后自动上传服务器

ins518 2024-09-24 18:02:03 技术文章 11 ℃ 0 评论

需求

Git 全量打包和增量打包参考:全量打包和增量打包前端项目

打包后会在项目根目录下生成 zip 压缩包。

上线需要将此压缩包文件上传到服务器。

这里通过代码实现自动上传功能

思路

  • 在服务器端实现文件上传的功能。这里使用 koa 实现
  • 文件上传需要 post 方式提交,请求内容格式为 Content-Type: multipart/form-data
  • 可以使用 koa-multer 实现文件上传。这里使用 koa-body 实现
  • 客户端发送 http 请求使用 curl。可以到curl for windows下载安装包安装
  • 命令格式:curl -F "type=myproject/web" -F "user=sch" -F "action=upload" -F file=@"./project_202011061049.zip" http://192.168.1.10:3000/upload
  • 服务器端根据 user 和 action 参数判断是否是有效请求。有效请求的话,文件放到服务器的 type 参数目录下
  • 需要先递归判断目录是否存在,如果不存在则新建
  • path 里面有个 parse() 方法,可以获取父级目录
// 在 Linux 中
path.parse('/目录1/目录2/文件.txt');
// 返回:
// {
//   root: '/',
//   dir: '/目录1/目录2',
//   base: '文件.txt',
//   ext: '.txt',
//   name: '文件'
// }

// 在 Windows 中
path.parse('C:\\目录1\\目录2\\文件.txt');
// 返回:
// {
//   root: 'C:\\',
//   dir: 'C:\\目录1\\目录2',
//   base: '文件.txt',
//   ext: '.txt',
//   name: '文件'
// }

实现

服务器端实现

初始化项目

  • 新建项目目录 server
  • 打开 cmd,切换到项目目录下,输入 npm init -y 生成 package.json 文件
  • 在项目目录下新建 public 目录,用来存放静态文件
  • 在项目目录下新建 src 目录,用来存放源代码
  • 在 src 目录下新建 server.js 文件,作为服务器启动文件

使用ES6、7语法

安装 babel,使用 import、 export、 async await 等语法

  • 安装:npm install @babel/core @babel/cli @babel/preset-env @babel/register @babel/node @babel/plugin-transform-runtime
  • 在根目录下新建 .babelrc 文件
{
  "presets": ["@babel/preset-env"],
  "plugins": [
    ["@babel/plugin-transform-runtime"]
  ]
}
  • 在 src 目录下新建 index.js
require('@babel/register')
require('./server')

自动重启

开发过程中,修改代码之后,需要重启才能看到最新的效果

这里使用 nodemon 来自动重启

  • 安装:npm i nodemon --save-dev

代码实现

  • 安装 koa 相关插件:npm i koa koa-router koa-body koa-static koa2-cors
  • 修改 src/server.js 文件
import path from 'path'
import Koa from 'koa'
import cors from 'koa2-cors'
import koaStatic from 'koa-static'
import koaBody from 'koa-body'
import Router from 'koa-router'
import apiRouter from './router'

const app = new Koa()
const router = new Router()

// cors - 这个例子其实用不到
app.use(cors({
  origin: function(ctx) {
    return '*'
  },
  exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'],
  maxAge: 5,
  credentials: true,
  allowMethods: ['GET', 'POST', 'DELETE'],
  allowHeaders: ['Content-Type', 'Authorization', 'Accept'],
}))

// 静态文件
app.use(koaStatic(path.join(__dirname, '../public')))

// post请求数据接收。
// 配置 formidable.uploadDir 后文件会自动上传到配置的目录
// 不配置formidable.uploadDir 文件会自动上传到系统的 tmp 目录
app.use(koaBody({
  multipart: true,  // 支持文件上传
  // formidable: { 
  //   uploadDir: path.join(__dirname, 'public/'),
  //   keepExtensions: true,  //  保存图片的扩展名
  // }
}))

router.use('', apiRouter.routes())
app.use(router.routes()).use(router.allowedMethods())

app.listen(3000, () => {
  console.log('server is started at part: 3000')
})
  • 在 src 目录下新建 router.js 文件
import Router from 'koa-router'
const router = new Router()

router.post('/upload', async (ctx) => {
  const { type, user, action } = ctx.request.body
  const file = ctx.request.files && ctx.request.files.file
  console.log(type, user, action)
  console.log(file)
  ctx.body = {
    code: 0
  }
})

export default router
  • 我们需要先根据传过来的参数 type 判断对应目录是否存在,如果不存在新建目录
import fs from 'fs'
import path from 'path'

/**
 * 同步递归创建路径
 *
 * @param  {string} dir   处理的路径
 * @param  {function} cb  回调函数
 */
const $mkdir = function(dir, cb) {
  const pathinfo = path.parse(dir)
  if (!fs.existsSync(pathinfo.dir)) {
    $mkdir(pathinfo.dir, function() {
      fs.mkdirSync(pathinfo.dir)
    })
  }
  cb && cb()
}

$mkdir(path.join(__dirname, 'demo/test/123/'))
  • 这里我们需要异步方案。在 src 目录下新建 utils 目录
  • 在 src/utils 目录下新建 mkdir.js 文件
import fs from 'fs'
import path from 'path'

// 异步自动创建路径
class Mkdir {
  // 开始处理一个路径
  async start(dir) {
    // 获取路径
    const pathStat = await this.getStat(dir)

    if (pathStat) {
      // 路径存在:是目录返回true,不是目录返回false
      return pathStat.isDirectory()
    }
    // 路径不存在,需要判断上一级路径是否存在。只有上一层路径存在,才能执行新建目录操作
    const pathinfo = path.parse(dir)

    // 递归处理上一级路径
    const status = await this.start(pathinfo.dir)
    // 上一级路径处理失败,返回失败
    if (!status) {
      return false
    }

    // 上一级路径有了,才能再创建当前级目录
    const mkdirStatus = await this.mkdir(dir)
    // 返回当前级目录创建成功与否
    return mkdirStatus
  }

  // 获取路径Stat
  getStat(loadpath) {
    return new Promise((resolve, reject) => {
      fs.stat(loadpath, (err, stats) => {
        if (err) {
          resolve(false)
        } else {
          resolve(stats)
        }
      })
    })
  }

  // 创建目录
  mkdir(dir) {
    return new Promise((resolve, reject) => {
      fs.mkdir(dir, (err) => {
        if (err) {
          console.log(err)
          resolve(false)
        } else {
          resolve(true)
        }
      })
    })
  }
}

const mkdir = new Mkdir()

export default (dir) => mkdir.start(dir)
  • 修改 src/router.js 文件
import path from 'path'
import fs from 'fs'
import Router from 'koa-router'
import mkdir from './utils/mkdir'

const router = new Router()

router.post('/upload', async (ctx) => {
  const { type, user, action } = ctx.request.body
  const file = ctx.request.files && ctx.request.files.file

  if (user != 'sch' || action != 'upload') {
    ctx.throw(401, 'parameter error')
  }

  // 创建可读流
  const reader = fs.createReadStream(file.path)

  // const dirPath = path.join(__dirname, '../public/', type)
  // 用上面的写法也可以
  // 这里换一种写法:process.cwd() - 表示命令运行时所在的目录
  const dirPath = path.join(process.cwd(), 'public/', type)
  const mkdirStatus = await mkdir(dirPath)
  if (!mkdirStatus) {
    ctx.throw(404, 'make directory error')
  }

  const uploadPath = dirPath + `/${file.name}`
  //创建可写流
  const upStream = fs.createWriteStream(uploadPath)
  // 可读流通过管道写入可写流
  reader.pipe(upStream)

  ctx.body = {
    code: 0,
    msg: 'success',
    data: {
      url: `http://${ctx.headers.host}/${type}/${file.name}`
    }
  }
})

export default router

添加命令

开发环境:执行 npm run server 命令。使用 nodemon 自动重启,入口文件为 src/index.js 文件

线上环境:先执行 npm run build 命令打包,将 ES6/7 等语法转换成 ES5,然后再执行 npm run start 启动项目。不需要使用 nodemon 自动重启,入口文件为 dist/server.js

  • 修改 package.json 文件,添加 scripts
{
  // ...
  "scripts": {
    "server": "nodemon ./src/index.js",
    "build": "babel src --out-dir dist",
    "start": "node ./dist/server.js",
    // ...
  },
  // ...
}
  • 代码放在服务器上面启动。可以使用 Nginx 配置一个代理,比如代理到 8080 端口等。

客户端实现

  • 到curl for windows下载安装包安装
  • 打开 cmd,输入 curl --version 测试是否安装成功
  • 修改 post-push-full.batpost-push.bat 文件,在打包完成后添加打包命令
:: ...

IF "%current_branch%"=="master" (
  :: ...

  :: http://192.168.1.10:3000/upload 是服务器端提供的上传地址
  :: 如果使用代理的话可能就变成了 http://192.168.1.10:8080/upload
  curl -F "type=myproject/web" -F "user=sch" -F "action=upload" -F file=@"%output%" http://192.168.1.10:3000/upload

  pause
)

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表