Skip to content

WEB端直传文件到微信云托管/腾讯云存储

背景

后端服务部署在微信小程序云托管中,前端自建vue项目单独部署在微信云托管的静态资源存储中。通过后端服务提供的上传图片的接口,然后上传到云托管的对象存储,如果图片超过1M请求报错:413 Request Entity Too Large,且无法修改限制的1M大小,所以需要前端实现文件的上传处理。 Description

准备

1、官方文档:

微信小程序: 开发指引 /对象存储 /服务端和其他客户端 /COS-SDK服务端使用

腾讯云:文档中心>对象存储>SDK 文档>JavaScript SDK>快速入门

2、权限的调整:微信云托管默认依托于公众号、小程序,纯web网页是无法获取微信的用户信息的,所以需要自建用户体系进行用户的权限处理;另外需要修改对象存储中权限的调整,如图: Description

3、安全域名的配置:文件直传云托管需要调用微信的服务,不配置的话会涉及到跨域问题,image.png

4、云调用配置 image.png

注意api.weixin.qq.com 相关接口前端不能直接调用,需要服务端的配合

思路

1、引入相关sdk: cos-js-sdk-v5

2、获取临时秘钥:通过服务端去调用云调用中配置的 /_/cos/getauth,获取临时密钥相关参数;

3、设置对应的存储桶、存储区域(在云托管对象存储中可查看);

4、文件的选择上传(同时需要定义存储在桶里的对象键,通常用于表示文件的上传路径以及文件名称,如果重复会导致文件上传后覆盖);

5、上传成功后是拿不到图片的完整路径的,需要自定义拼接(根据对象存储中的外网地址+对象键),或者根据后端服务器获取;

示例

新建html直接复制下方代码并调整配置即可:

html
		<!-- 选择要上传的文件 -->
    <input id="fileSelector" type="file" />
    <!-- 点击按钮上传 -->
    <input id="submitBtn" type="submit" />
	 <script src="https://cdn.jsdelivr.net/npm/cos-js-sdk-v5/dist/cos-js-sdk-v5.min.js"></script>
	 <script>
      var cos = null;
      function request(url, method = "GET", data = null) {
        return new Promise(function (resolve, reject) {
          const xhr = new XMLHttpRequest();
          xhr.withCredentials = true;
          xhr.addEventListener("readystatechange", function () {
            if (this.readyState === 4) {
              resolve(this.responseText);
            }
          });

          xhr.open(method, url);
          // 添加header
          xhr.setRequestHeader("Content-Type", "application/json");
          xhr.setRequestHeader(
            "Authorization",  "xxxxx"
          );
          xhr.send(data);
        });
      }
      cos = new COS({
        getAuthorization: function (options, callback) {
          // 异步获取临时密钥
          request( "自定义实现获取临时密钥的后端服务,调用"
          ).then((res) => {
            let data = JSON.parse(res).result.body;
            console.log(data)
            let startTime = Math.floor(Date.now() / 1000);
            callback({
              TmpSecretId: data.TmpSecretId,
              TmpSecretKey: data.TmpSecretKey,
              SecurityToken: data.Token,
              // 建议返回服务器时间作为签名的开始时间,避免客户端本地时间偏差过大导致签名错误
              StartTime: startTime, // 时间戳,单位秒,如:1580000000
              ExpiredTime: data.ExpiredTime, // 时间戳,单位秒,如:1580000000
              ScopeLimit: true, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用
            });
          });
        },
      });
      function handleFileInUploading(file) {
        cos.uploadFile(
          {
            Bucket: "xxx" /* 填写自己的 bucket,必须字段 */,
            Region: "xxx" /* 存储桶所在地域,必须字段 */,
            Key: "/test/xxx.jpg" /* 存储在桶里的对象键(例如:1.jpg,a/b/test.txt,图片.jpg)支持中文,必须字段 */,
            Body: file, // 上传文件对象
            SliceSize:  1024 * 1024 *  5 /* 触发分块上传的阈值,超过5MB使用分块上传,小于5MB使用简单上传。可自行设置,非必须 */,
            onProgress: function (progressData) {
              console.log(JSON.stringify(progressData));
            },
          },
          function (err, data) {
            if (err) {
              console.log("上传失败", err);
            } else {
              console.log("上传成功");
            }
          }
        );

        return;
      }
      /* 选择文件 */
      document.getElementById("submitBtn").onclick = function (e) {
        const file = document.getElementById("fileSelector").files[0];
        if (!file) {
          document.getElementById("msg").innerText = "未选择上传文件";
          return;
        }
        handleFileInUploading(file);
      };
    </script>

如果是vue、react等环境下可以参考腾讯云-对象存储文档下的描述自定义调整引入使用:

image.png

Released Under The MIT License.