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

这里写目录标题

一、文件上传

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";
    }
}
相关推荐
言乐611 小时前
Python实现可运行解密游戏游戏框架
python·游戏·小程序·游戏程序·关卡设计
2501_9151063221 小时前
iOS 软件测试工具性能监控、日志分析 KeyMob、Instruments等
android·ios·小程序·https·uni-app·iphone·webview
云迈科技-软件定制开发1 天前
2026 AI智能体小程序APP开发怎么做:从场景规划到上线交付的完整参考
大数据·人工智能·小程序
小码哥0681 天前
医院陪诊小程序怎么开发-医院陪诊小程序源码功能-微信小程序 医院健康陪诊陪护系统
微信小程序·小程序·医院陪诊·陪诊系统·陪诊陪诊
黄华SJ520it2 天前
柯尔嫚商城模式开发:从概念到实现的完整指南
小程序·系统开发
黄华SJ520it3 天前
线上线下多门店融合系统开发指南
小程序·系统开发
一孤程3 天前
Airtest自动化测试第五篇:小程序与Web测试——跨平台自动化全覆盖
前端·自动化测试·小程序·自动化·测试·airtest
CRMEB定制开发4 天前
开源商城源码下载后怎么搭建?五步走通完整流程
小程序·开源·商城系统·私域运营
小羊Yveesss4 天前
2026年如何自己搭建一个外贸网页?单页验证和完整网站的区别
微信小程序·小程序·开源
weishuangyun1234 天前
怎么开发自己的小程序?2026 三种主流方式实测对比
小程序