小程序——文件上传和下载

这里写目录标题

一、文件上传

1.1、wx.uploadFile(Object object)

将本地资源上传到服务器。客户端发起一个 HTTPS POST 请求,其中 content-type 为 multipart/form-data。使用前请注意阅读相关说明。

参数:Object object

属性 类型 默认值 必填 说明
url string 开发者服务器地址
filePath string 要上传文件资源的路径 (本地路径)
name string 文件对应的 key,开发者在服务端可以通过这个 key 获取文件的二进制内容
header Object HTTP 请求 Header,Header 中不能设置 Referer
formData Object HTTP 请求中其他额外的 form data
timeout number 超时时间,单位为毫秒
enableProfile boolean true 是否开启 profile。iOS 和 Android 端默认开启,其他端暂不支持。开启后可在接口回调的 res.profile 中查看性能调试信息。
enableHttp2 boolean false 是否开启 http2
enableQuic boolean false 是否开启 Quic/h3 协议(iOS 微信目前使用 gQUIC-Q43;Android 微信在 v8.0.54 前使用 gQUIC-Q43,v8.0.54 开始使用 IETF QUIC,即 h3 协议;PC微信使用 IETF QUIC,即 h3 协议)
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(调用成功、失败都会执行)

object.success 回调函数:

参数:Object res

属性 类型 说明
data string 开发者服务器返回的数据
statusCode number 开发者服务器返回的 HTTP 状态码
profile Object 网络请求过程中一些调试信息,查看详细说明。目前 iOS 和 Android 端支持。

示例:

js 复制代码
wx.chooseImage({
  success (res) {
    const tempFilePaths = res.tempFilePaths
    wx.uploadFile({
      url: 'https://example.weixin.qq.com/upload', //仅为示例,非真实的接口地址
      filePath: tempFilePaths[0],
      name: 'file',
      formData: {
        'user': 'test'
      },
      success (res){
        const data = res.data
        //do something
      }
    })
  }
})

1.2、返回值UploadTask

一个可以监听上传进度变化事件,以及取消上传任务的对象

方法:

  • UploadTask.abort()
    中断上传任务
  • UploadTask.onProgressUpdate(function listener)
    监听上传进度变化事件
  • UploadTask.offProgressUpdate(function listener)
    移除上传进度变化事件的监听函数
  • UploadTask.onHeadersReceived(function listener)
    监听 HTTP Response Header 事件。会比请求完成事件更早
  • UploadTask.offHeadersReceived(function listener)
    移除 HTTP Response Header 事件的监听函数

示例:

js 复制代码
const uploadTask = wx.uploadFile({
  url: 'http://example.weixin.qq.com/upload', //仅为示例,非真实的接口地址
  filePath: tempFilePaths[0],
  name: 'file',
  formData:{
    'user': 'test'
  },
  success (res){
    const data = res.data
    //do something
  }
})

uploadTask.onProgressUpdate((res) => {
  console.log('上传进度', res.progress)
  console.log('已经上传的数据长度', res.totalBytesSent)
  console.log('预期需要上传的数据总长度', res.totalBytesExpectedToSend)
})

uploadTask.abort() // 取消上传任务

1.3、案例

uploadFile.wxml

html 复制代码
<view class="container">
  <button bind:tap="upfile">选择上传文件</button>
</view>
<view class="container" wx:if="{{backFlag}}">
  <text>上传成功后回显</text>
  <image src="{{backImgUrl}}"></image>
</view>

uploadFile.js

js 复制代码
var app = getApp();
Page({
  data: {
    backFlag: false,
    backImgUrl: null,
  },
  //事件处理函数
  upfile: function() {
    wx.chooseMedia({
      success: (res) => {
        var that = this;
        var tempFilePaths = res.tempFiles
        wx.uploadFile({
          url: "http://127.0.0.1:8080/upload",
          header: {"Content-Type": "multipart/form-data"},
          filePath: tempFilePaths[0].tempFilePath,
          name: 'uploadFile',
          formData: {

          },
          success(res) {
            console.log(res.data)
            that.setData({
              backFlag: true,
              backImgUrl: res.data
            })
          }
        })
      }
    })
  },
  onLoad: function() {

  }
})
java 复制代码
package pers.zhang.controller;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

/**
 * @Author: acton_zhang
 * @Date: 2026/3/6 下午10:55
 * @Version 1.0
 */
@RestController
public class FileController {

    final public static String UPLOAD_PATH_PREFIX = "uploadFile/";

    @PostMapping("/upload")
    public String upload(MultipartFile uploadFile, HttpServletRequest request) {
        if (uploadFile.isEmpty()) {
            //返回选择文件提示
            return "请选择上传文件";
        }
        //构建文件上传所要保存的"文件夹路径"--这里是相对路径,保存到项目根路径的文件夹下
        String realPath = new String("src/main/resources/" + UPLOAD_PATH_PREFIX);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/");
        String format = sdf.format(new Date());
        //存放上传文件的文件夹
        File file = new File(realPath + format);
        System.out.println("上传文件保存的路径:" + file.getAbsolutePath());

        if (!file.isDirectory()) {
            file.mkdirs();
        }
        //获取原始文件名
        String oName = uploadFile.getOriginalFilename();
        String newName = UUID.randomUUID().toString() + oName.substring(oName.lastIndexOf("."), oName.length());

        try {
            //构建真实的文件路径
            File newFile = new File(file.getAbsolutePath() + File.separator + newName);
            //转存文件到指定路径,如果文件名重复的话,将会覆盖掉之前的文件,这里是把文件上传到 "绝对路径"
            uploadFile.transferTo(newFile);
            String filePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/uploadFile/" + format + newName;
            System.out.println("返回的访问路径:" + filePath);
            return filePath;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "上传失败";
    }
}
java 复制代码
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
        registry.addResourceHandler("/uploadFile/**").addResourceLocations("file:/Users/acton_zhang/J2EE/MavenWorkSpace/wx_pro/src/main/resources/uploadFile/");
    }
}

二、下载

2.1、wx.downloadFile(Object object)

下载文件资源到本地。客户端直接发起一个 HTTPS GET 请求,返回文件的本地临时路径 (本地路径),单次下载允许的最大文件为 200MB。使用前请注意阅读相关说明。

注意:请在服务端响应的 header 中指定合理的 Content-Type 字段,以保证客户端正确处理文件类型。

参数:Object object

属性 类型 默认值 必填 说明
url string 下载资源的 url
header Object HTTP 请求的 Header,Header 中不能设置 Referer
timeout number 60000 超时时间,单位为毫秒,默认值为 60000 即一分钟。
filePath string 指定文件下载后存储的路径 (本地路径)
enableProfile boolean true 是否开启 profile。iOS 和 Android 端默认开启,其他端暂不支持。开启后可在接口回调的 res.profile 中查看性能调试信息。
enableHttp2 boolean false 是否开启 http2
enableQuic boolean false 是否开启 Quic/h3 协议(iOS 微信目前使用 gQUIC-Q43;Android 微信在 v8.0.54 前使用 gQUIC-Q43,v8.0.54 开始使用 IETF QUIC,即 h3 协议;PC微信使用 IETF QUIC,即 h3 协议)
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(调用成功、失败都会执行)

object.sucess回调函数:

参数Object res:

属性 类型 说明
tempFilePath string 临时文件路径 (本地路径)。没传入 filePath 指定文件存储路径时会返回,下载后的文件会存储到一个临时文件
filePath string 用户文件路径 (本地路径)。传入 filePath 时会返回,跟传入的 filePath 一致
statusCode number 开发者服务器返回的 HTTP 状态码
profile Object 网络请求过程中一些调试信息,查看详细说明。目前 iOS 和 Android 端支持。

示例:

js 复制代码
wx.downloadFile({
  url: 'https://example.com/audio/123', //仅为示例,并非真实的资源
  success (res) {
    // 只要服务器有响应数据,就会把响应内容写入文件并进入 success 回调,业务需要自行判断是否下载到了想要的内容
    if (res.statusCode === 200) {
      wx.playVoice({
        filePath: res.tempFilePath
      })
    }
  }
})

2.2、返回值DownloadTask

一个可以监听下载进度变化事件,以及取消下载任务的对象

方法:

  • DownloadTask.abort()
    中断下载任务
  • DownloadTask.onProgressUpdate(function listener)
    监听下载进度变化事件
  • DownloadTask.offProgressUpdate(function listener)
    移除下载进度变化事件的监听函数
  • DownloadTask.onHeadersReceived(function listener)
    监听 HTTP Response Header 事件。会比请求完成事件更早
  • DownloadTask.offHeadersReceived(function listener)
    移除 HTTP Response Header 事件的监听函数

示例:

js 复制代码
const downloadTask = wx.downloadFile({
  url: 'http://example.com/audio/123', //仅为示例,并非真实的资源
  success (res) {
    wx.playVoice({
      filePath: res.tempFilePath
    })
  }
})

downloadTask.onProgressUpdate((res) => {
  console.log('下载进度', res.progress)
  console.log('已经下载的数据长度', res.totalBytesWritten)
  console.log('预期需要下载的数据总长度', res.totalBytesExpectedToWrite)
})

downloadTask.abort() // 取消下载任务

2.3、示例

在函数dian中调用了wx.downloadFile()接口,下载成功,图片就会保存在res.tempFilePath中,再把res.tempFilePath设置为头像。在函数dian2中,通过wx.savelmage ToPhotosAlbum()接口把下载成功的图片保存到手机相册。

downloadFile.wxml

html 复制代码
<view class="container">
  <view bind:tap="dian" class="userinfo">
    <image class="userinfo-avatoar" src="{{avatar}}" background-size="cover"></image>
    <text class="userinfo-nickname">{{userInfo.nickName}}</text>
  </view>
  <view class="usermotto">
    <image src="http://127.0.0.1:8080/download/bd22f30a-c83a-41b2-aa0d-8b272fd41ac8.jpeg" class="tu"></image>
    <view bind:tap="dian2">下载上图</view>
  </view>
</view>

downloadFile.js

js 复制代码
var app = getApp();
Page({
  data: {
    motto: 'Hello World',
    userInfo: {},
    avatar: null
  },
  dian: function() {
    wx.downloadFile({
      url: 'http://127.0.0.1:8080/download/bd22f30a-c83a-41b2-aa0d-8b272fd41ac8.jpeg',
      type: 'image',
      success: (res) => {
        console.log(res)
        this.setData({
          avatar: res.tempFilePath
        })
      }
    })
  },
  onLoad: function() {
    this.setData({
      userInfo: {"nickName": "tom"}
    })
  },
  dian2: function(){
    wx.downloadFile({
      url: 'http://127.0.0.1:8080/download/bd22f30a-c83a-41b2-aa0d-8b272fd41ac8.jpeg',
      success: (res) => {
        console.log(res);
        var rr = res.tempFilePath;
        wx.saveImageToPhotosAlbum({
          filePath: rr,
          success: (res) => {
            wx.showToast({
              title: "保存成功",
              icon: "success",
              duration: 2000
            })
          }
        })
      }
    })
  }
})
java 复制代码
@GetMapping("/download/{filename}")
public void down(@PathVariable("filename") String filename, HttpServletResponse response) throws IOException {
    File file = new File(DOWNLOAD_PATH_PREFIX + filename);
    if (!file.exists()) {
        response.sendError(HttpServletResponse.SC_NOT_FOUND);
        return;
    }

    // 设置响应头
    response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
            "attachment; filename=\"" + file.getName() + "\"");
    response.setContentLength((int) file.length());
    response.setContentType(determineContentType(filename));

    // 写入文件流
    try (InputStream inputStream = new FileInputStream(file);
         OutputStream outputStream = response.getOutputStream()) {

        byte[] buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
    }
}

private String determineContentType(String filename) {
    String extension = filename.substring(filename.lastIndexOf(".") + 1, filename.length());
    switch (extension) {
        case "pdf": return "application/pdf";
        case "txt": return "text/plain";
        case "jpg":
        case "jpeg": return "image/jpeg";
        case "png": return "image/png";
        default: return "application/octet-stream";
    }
}
相关推荐
wuyoula16 小时前
全新多平台电商代付商城源码
开发语言·c++·ui·小程序·php源码
低代码布道师16 小时前
微搭低代码MBA 培训管理系统实战 36——小程序端课程预约功能实现
低代码·小程序
万岳科技系统开发17 小时前
小程序直播架构调整指南:H5嵌套模式的优化与替代方案
小程序·架构
Greg_Zhong18 小时前
学习AI 工程师第 3 天:小程序中调用豆包模型,实现ai助手(打字机效果与流式输出)
小程序·ai工程师·小程序调用豆包实现ai助手
于先生吖18 小时前
家政派单小程序定制厂家
大数据·小程序
00后程序员张19 小时前
完整指南 iOS App上架到App Store的步骤详解
macos·ios·小程序·uni-app·objective-c·cocoa·iphone
久爱@勿忘20 小时前
uniappH5跳转小程序
前端·小程序·uni-app
文慧的科技江湖2 天前
光储充一体化开源能源管理系统 需求说明书(简单版) - 慧知开源充电桩平台
小程序·开源·能源·光储充·光伏系统·实现光储充全设备统一监控·光储充一体化开源能源管理系统
eric*16882 天前
Mac反编译小程序教程
小程序·小程序反编译
打瞌睡的朱尤2 天前
微信小程序50~75
微信小程序·小程序