鸿蒙文件上传-从前端到后端详解,对比jq请求和鸿蒙arkts请求区别,对比new FormData()和鸿蒙arktsrequest.uploadFile

需要权限:ohos.permission.INTERNET

1.nodejs自定义书写上传后端接口

传输过来的数据放在files?.image下

复制代码
router.post('/upload',(req, res) => {
  var form = new multiparty.Form();
  form.uploadDir='public/images/uploads'; //上传图片保存的地址(目录必须存在)
  form.parse(req, function(err, fields, files) {// 1、fields:获取表单的数据 2、files:图片上传成功返回的信息
    console.log(files,fields)
    const fileurl = Date.now()+ files?.image[0]?.originalFilename;

    let newPath = form.uploadDir + '/' +fileurl
    fs.renameSync(files.image[0].path,newPath);
    let imgUrl = myUrl.myUrl+'/images/uploads/' +fileurl
    
    res.send({
      code: '200',
      message: '数据上传成功',
      data:imgUrl
    })
  })
})

2,在jq中请求(new FormData())

复制代码
        var fileImg;
        //读取图片
        function fileUpload(_this) {
            var fileReader = new FileReader();//创建文件读取对象
            fileImg = _this.files[0];//获取file组件中的文件
        }
        //上传图片
        function uploadPictures() {
            var formData = new FormData();
            //图片
            if (fileImg != null) {
              formData.append("image", fileImg);
            }
            $.ajax({
             url: 'http://localhost:3333/api/img/upload',
                type: 'post',
                data: formData,
                processData: false,
                contentType: false,
                success: function (res) {
                    // var res = JSON.parse(res);
                    console.log('upload success', res);
                    // $('.img').attr('src', res.path);
                    debugger
                },
                error: function (err) {
                    console.log('upload error', err);
                    console.log(err);
                }
            });
        }

3.对比在鸿蒙arkts请求如下 -试用相册的场景

参考官网

1.假设数据来源于相册,以下是获取相册的数据,photoSelectResult.photoUris[0]是一个目录的路径, 但是不是context.cacheDir的路径,

试用下载必须要在cacheDir目录下面

复制代码
 async selectPhoto() {
    try {
      let PhotoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
      PhotoSelectOptions.maxSelectNumber = 1;
      PhotoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;
      let textInfo: photoAccessHelper.TextContextInfo = {
        text: '人像'
      };
      let recommendationOptions: photoAccessHelper.RecommendationOptions = {
        textContextInfo: textInfo
      };
      PhotoSelectOptions.recommendationOptions =
        recommendationOptions; // 将推荐参数赋值给 photoSelectOptions.recommendationOptions
      let photoPicker = new photoAccessHelper.PhotoViewPicker();
      let photoSelectResult = await photoPicker.select(PhotoSelectOptions)
      if (photoSelectResult.photoUris.length == 1) {
        this.uploadFile(photoSelectResult.photoUris[0])
      }
    } catch (error) {
      let err: BusinessError = error as BusinessError;
    }
  }

2.因为必须是cacheDir目录,从相册拿到的的图片就复制一份存在cacheDir

复制代码
  // 提取文件扩展名的函数
  getFileExtension(fileName: string): string {
    const lastDotIndex = fileName.lastIndexOf('.');
    if (lastDotIndex !== -1 && lastDotIndex < fileName.length - 1) {
      return fileName.slice(lastDotIndex + 1);
    }
    return '';
  }
。。。。。
    console.log('photoUris', photoUris)
    const extensionName = this.getFileExtension(photoUris) // 后缀名
    console.log('文件扩展名是:', extensionName);
    const cacheDir = context.cacheDir; // 缓存根目录
    const names = 'phone' + Date.now() + '.' + extensionName // 文件名
    const cacheF = cacheDir + '/' + names // 缓存目录路径
    let file: fileIo.File | undefined;
    file = fileIo.openSync(photoUris, fileIo.OpenMode.READ_ONLY); // 打开现有的文件
    fileIo.copyFileSync(file.fd, cacheF); //复制一下到缓存文件
    fileIo.closeSync(file); // 关闭
    console.log('文件扩展名是:', extensionName, '----', names);

3。知道了cacheDir目录就组装参数

复制代码
   let files: Array<request.File> = [
    //uri前缀internal://cache 对应cacheDir目录
      {
        filename: names,
        name: 'image',  // 必须是image,因为接口拿的数据就是这个的第0项
        uri: 'internal://cache/' + names,
        type: extensionName
      }
    ]

let data: Array = [{ name: 'name', value: 'value' }];
    let uploadConfig: request.UploadConfig = {
      url: 'http://xxxxxxxxxxxxxxxx/api/img/upload',
      header: {
      // 根据项目添加
},
      method: 'POST',
      files: files,
      data: data,
    }

// 将本地应用文件上传至网络服务器
try {
  request.uploadFile(context, uploadConfig)
    .then((uploadTask: request.UploadTask) => {
 let headerCallback = (value: object) => {
            let str = JSON.stringify(value)
            
            console.log("http:success:", JSON.stringify(rstr ))
          };
 uploadTask.on('headerReceive', headerCallback);
    })
    .catch((err: BusinessError) => {
      console.error(`Invoke uploadFile failed, code is ${err.code}, message is ${err.message}`);
    })
} catch (error) {
  let err: BusinessError = error as BusinessError;
  console.error(`Invoke uploadFile failed, code is ${err.code}, message is ${err.message}`);
}

缓存目录在cacheDir ="/data/app/el2/100/base/{找到自己的包名}/haps/entry/cache"

原理总结

使用相册拿到的路径,复制一份放在缓存路径下, request.uploadFile(只能读缓存的路径。

通过 uploadTask.on('headerReceive', headerCallback);拿到后端给我们的响应数据code

官网也还提供了request.agent,可查看文档使用

https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/app-file-upload-download#上传应用文件

相关推荐
BillKu23 分钟前
Vue3中AbortController取消请求的用法详解
前端·javascript·vue.js
特立独行的猫a35 分钟前
HarmonyOS NEXT 诗词元服务项目开发上架全流程实战(二、元服务与应用APP签名打包步骤详解)
华为·打包发布·harmonyos·应用签名·appgallery
heroboyluck1 小时前
rust 全栈应用框架dioxus
前端·rust·dioxus
不思念一个荒废的名字2 小时前
【黑马JavaWeb+AI知识梳理】后端Web基础01 - Maven
java·前端·maven
hunteritself2 小时前
OpenAI 上新:轻量版 Deep Research、GPT-4o 升级、o3 限额翻倍、生图 API 发布!| AI Weekly 4.21-4.27
前端·人工智能·科技·深度学习·chatgpt
刺客-Andy2 小时前
React 第三十六节 Router 中 useParams 的具体使用及详细介绍
前端·react.js·前端框架
A富得流油的咸鸭蛋3 小时前
harmonyOS 手机,双折叠,平板,PC端屏幕适配
智能手机·电脑·harmonyos
黄同学real3 小时前
Vue 项目中运行 `npm run dev` 时发生的过程
前端·vue.js·npm
黄同学real3 小时前
vue 优化策略,大白话版本
前端·javascript·vue.js
xcLeigh3 小时前
HTML5好看的水果蔬菜在线商城网站源码系列模板8
java·前端·html5