AntSwordProject / antSword

中国蚁剑是一款跨平台的开源网站管理工具。AntSword is a cross-platform website management toolkit.
https://www.yuque.com/antswordproject/antsword
MIT License
3.64k stars 578 forks source link

使用Custom类型连接shell上传文件时,无法判断当前文件是否该追加还是覆盖 #358

Open R1chCat opened 3 weeks ago

R1chCat commented 3 weeks ago

报告 Bug


BUG

BUG描述


当使用Custom类型的shell上传文件时,参数如下

'z1': '#{path}',
'z2': '#{buffer::content}'

被上传文件长度只需要一次上传时和需要分批次上传时的参数一样,遇到以下场景时无法判断是该追加内容还是覆盖内容到服务器上的文件:

## 场景1
服务器文件:
    1.data
被上传文件:
    1.data 长度 1kb

## 场景2
服务器文件:
    1.data
被上传文件:
    1.data 长度 10mb

antsword在处理场景1时只发送一个请求,只需进行覆盖操作即可完成上传 antsword在处理场景2时会发送多个请求,需要进行追加操作,你无法仅通过z1z2两个参数来判断当前上传文件的操作是多个请求还是一个请求,所以无法判断是进行覆盖还是追加操作,这就导致后端只能进行追加操作,如果服务器文件不存在时这样没有问题,如果存在时则会导致上传的内容是在原有文件上追加之后的内容

BUG解决方案

这个问题的本质是antsword的文件上传操作的无状态导致后端无法判断哪次请求是第一次请求(只有第一次请求需要覆盖操作)

所以可以添加一个z3参数不管是bool或者int(当前上传文件次数)能判断当前请求是第一个上传请求就都可以达到目的

最后

感谢师傅的维护🙏

R1chCat commented 3 weeks ago

看了下代码,修改以下两个文件即可解决这个问题

source\core\custom\template\filemanager.js

  upload_file: {
    _: 'U',
    'z1': '#{path}',
    'z2': '#{buffer::content}',
    'z3': '#{count}',
  },

下面的代码只是在请求中多加了一个参数,唯一不确定的是这样操作会不会对其他类型的shell有何影响 source\modules\filemanager\index.js

          // 开始上传
          const uploadBuffFunc = (_buff, length) => {
            new Promise((res, rej) => {
              let _b = _buff.shift();
              if (_b) {
                res(_b);
              } else {
                // 上传完毕
                task.success(LANG['upload']['task']['success']);
                toastr.success(LANG['upload']['success'](fileName), LANG_T['success']);
                // 刷新缓存
                this.files.refreshPath(path === this.path ? '' : path);
                // 继续上传
                return upload();
              }
            }).then((b) => {
              // 更新进度条
              task.update(`${parseInt((buffLength - (b.length * _buff.length)) / buffLength * 100)}%`);
              this.core.request(
                this.core.filemanager.upload_file({
                  path: path + fileName,
                  content: b,
                  count: length-_buff.length,
                })
              ).then((res) => {
                let ret = res['text'];
                if (ret === '1') {
                  return uploadBuffFunc(_buff, length);
                }
                task.failed(LANG['upload']['task']['failed'](ret));
                toastr.error(LANG['upload']['error'](
                  fileName,
                  ret === '0' ? '' : `<br/>${ret}`
                ), LANG_T['error']);
              }).catch((err) => {
                // 出错后友好提示
                let errmsg = err;
                if (err.hasOwnProperty('status') && err.hasOwnProperty('response')) {
                  errmsg = `${err.status} ${err.response.res.statusMessage}`;
                  switch (err.status) {
                    case 413:
                      errmsg += `${LANG['upload']['task']['httperr_413']}`;
                      break;
                    default:
                      break;
                  }
                } else if (err.hasOwnProperty('errno')) {
                  switch (err.errno) {
                    case 'ETIME':
                      errmsg = `${LANG['upload']['task']['httperr_etime']}`;
                      break;
                    case 'ECONNREFUSED':
                      errmsg = `${LANG['upload']['task']['httperr_econnrefused']}`;
                      break;
                    default:
                      errmsg = `${err.errno} ${err.code}`;
                      break;
                  }
                }
                task.failed(LANG['upload']['task']['error'](errmsg));
                toastr.error(LANG['upload']['error'](fileName, errmsg), LANG_T['error']);
              });
            })
          }
          uploadBuffFunc(buff, buff.length);
        });
Medicean commented 2 weeks ago

你理解的没什么问题,改动的地方不会对其它类型功能上有什么影响。

目前如果上传文件时,服务端有同名文件,只会追加。加入了 分片序号之后,也可以做断点续传功能了。后面可以一起讨论一下这块接口的设计。