一文搞定腾讯开发生态-微信上传图片和视频

先说场景:

用户通过微信打开页面,在上面可以上传图片、视频,也可以查看自己上传的图片和视频。

场景很简单,但是基本可以涉及到腾讯生态的常见开发技术。

一、需求调研

1.1、整理场景规则:

1、只能通过微信打开;

2、多用户使用,需要做用户隔离,每个用户的图片视频存放在自己标识的路径下;

3、不想购买服务器,也就是尽量使用Serverless;

1.2、梳理整体流程:

1、用户打开网页,浏览CDN托管的网页地址。

2、返回的网页中,需要访问云函数,进行安全信息的初始化和访问。

3、云函数访问微信接口,完成初始化,并返回安全信息。

4、用户获取到安全信息后,可以访问COS文件对象,访问时带上以上步骤获取的安全信息。

1.3、确定技术方案

场景基于微信环境,所以整体都考虑使用腾讯系产品:

页面 - 使用腾讯云的CDN托管静态网站

云函数 - 使用腾讯云的函数服务SCF

存储 - 使用腾讯云的对象存储COS

1.4、拆解开发步骤:

1、开发H5页面

2、部署存储方案

3、开发云函数,对接H5页面

4、完善H5页面,使用腾讯授权信息,开发上传和查询功能

二、开发H5页面

H5页面是用户的整个操作界面,包含上传和查看的功能。

可以直接用AI生成,现在各种AI平台,使用自己顺手的就行,比如直接用浏览器访问的kimi/deepseek/chatgpt:

帮我生成一个在微信端使用的H5页面。

这里我使用了开发工具 Trae IDE (国际版: Trae AI),大家可以选用自己顺手的AI辅助工具,如果有合适的也请推荐给我。

AI在这里针对微信环境做了相关判断,类似代码:

html 复制代码
<div id="wxOnly" class="wx-warning hidden">
    ⚠️ 请使用微信打开本页面
</div>
javascript 复制代码
// 1. 检测微信环境
if (!/MicroMessenger/i.test(navigator.userAgent)) {
    document.getElementById('wxOnly').classList.remove('hidden');
}

可以继续询问AI,完善整个页面:

这是一个在微信里面上传图片和视频的页面,请针对微信端进行页面优化。

一句话搞定一个页面(包括提示词中还有两个错别字,AI都完美理解)。直接本地运行查看效果,有一些bug或者调整都可以反复询问AI得到解决。

接下来我们要把这个页面部署到公网:使用腾讯云CDN来托管此页面。

三、部署存储方案

这里选择了腾讯云的CDN分发(用来托管H5页面)和COS存储桶(用来存储网站、上传的图片和视频)。

3.1、账号配置

1、注册腾讯云账号

2、完成实名认证

3.2、COS对象存储

快速入门:https://cloud.tencent.com/document/product/436/38484

1、开通COS服务,创建完后前往控制台: COS对象存储

2、创建存储桶,创建完后对应的存储桶列表: COS存储桶列表

通过上面步骤,创建两个存储桶 site存储桶(桶名:site-123456,用来存储静态网站,并托管给CDN) 和 upload存储桶(桶名:upload-123456,用来存储网页上传的图片和视频):

此时已经可以上传文件并进行访问。为了更好的满足场景,接下来进行存储桶的配置。

3.3、site存储桶 配置

site存储桶是用来托管网页的,所以需要开启静态网站。

1、开启静态网站

这一步让存储桶除了提供存储能力,还可以提供网站服务能力。

其中的访问节点即为公网访问地址,可以直接访问,只是这个地址又长又不好看,接下来我们优化一下。

2、自定义CDN加速域名

从上面可以看到,访问地址又长又长,这一步就是让这个访问即友好,又快捷。

选择 域名与传输管理 - 自定义CDN加速域名 - 添加域名:

这里有两种类型域名:

  • 自定义CDN加速域名,用自己的域名来访问存储的文件,而且还带了CDN的缓存和加速。
  • 自定义源站域名,用自己的域名来访问存储的文件,仅此而已。

所以我们这里选择的是CDN加速域名。

配置CDN域名信息:

这里的源站类型包含:默认源站/静态网站源站/全球加速源站。这里选择静态网站源站。

3、配置HTTPS证书

现在都在推HTTPS证书,能有的咱都要有,配置CDN的HTTPS证书需要转到CDN控制台: CDN证书配置

选择 证书管理 - 证书配置 - 更新:

填写证书信息:

这里填入证书内容,点击提交,然后在证书列表中看到证书状态为 "配置成功" 即可。

我们也可以在SSL证书管理界面(地址:https://console.cloud.tencent.com/ssl)查看所有的SSL证书:

到这里,我们有了一个配置完全的静态网站,带HTTPS,带加速分发,不再需要自己买服务器。接下来配置上传文件的存储桶。

3.4、upload存储桶 配置

1、自定义源站域名

选择 域名与传输管理 - 自定义源站域名 - 添加域名:

配置域名信息和类型:

这里的源站类型选择 默认源站,跟 site 存储桶的自定义域名有一点区别,点击创建就添加了自定义域名。接下来给自定义域名配置HTTPS证书。

2、配置HTTPS证书

选择 域名与传输管理 - 自定义源站域名 - 绑定证书:

这里上传证书信息:

到这里我们就配置好了 upload 桶的域名和HTTPS证书。

四、开发云函数,对接H5页面

在前面的步骤,已经部署好存储方案,接下来就可以用云函数来对接使用存储服务。

云函数的使用,主要是基于Serverless的需求,可以直接使用云函数来替换后台应用,而不需要自己搭建服务器来构建后台应用。

基于我们的技术方案,云函数需要对接腾讯来获取授权信息,同时对接前端来提供服务:

1、获取当前微信用户的openid,用来定义每个用户的存储路径;

2、获取对象存储COS的临时密钥,用来后续访问COS;

3、提供与前端页面对接的能力 - 函数URL;

4.1、云函数开发流程

这里分为三步来执行:

1、本地用相同的环境开发好代码;

2、然后再上传部署到云函数;

3、在线调整代码,并部署和测试;

4.2、本地开发代码

1、新建项目

代码结构如下:

node_modules:依赖库,将上传到云端

index.js: 入口脚本,将上传到云端

package.json: 项目配置,将上传到云端

package-lock.json: 项目锁定配置,将上传到云端

test.js: 本地测试文件,不需要上传

2、test.js
javascript 复制代码
// test.js
const { main_handler } = require('./index.js');   // 引入云函数入口

(async () => {
  const mockEvent = { body: JSON.stringify({ code: '123' }) }; // 模拟 API 网关事件
  const mockContext = { requestId: 'local-test' };
  const res = await main_handler(mockEvent, mockContext);
  console.log('返回结果:', res);
})();

这里模拟了云函数的运行环境,函数入参为 code,同时传递了事件信息和context信息。

3、index.js
javascript 复制代码
// 通过code获取微信用户的openid
async function getOpenId(code) {
  return {
    statusCode: 200,
    data: '123'
  }; 
}

// 获取cos的临时密钥
async function getCosAuth(openId) {
  return {
    statusCode: 200,
    data: 'abc'
  }; 
}

exports.main_handler = async (event) => {
  // 入参 code 必填
  const body = JSON.parse(event.body || '{}');
  const { code } = body;
  if (!code) {
    return {
      statusCode: 400,
      headers:{'Content-Type':'application/json'},
      body: JSON.stringify({
        error: '缺少code'
      })
    };
  }

  const openId = await getOpenId(code);
  const cosAuth = await getCosAuth(openId);
  return {
    statusCode: 200,
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({cosAuth:cosAuth, openid:openId})
  };
};

其中的main_handler为入口函数,同时获取cos临时密钥和openid,这里先定义过程和结构,后续可以用实际获取代码来替换。

4、package.json
javascript 复制代码
{
  "name": "scfDemoCode",
  "version": "1.0.0",
  "main": "index.js",
  "dependencies": {
    "qcloud-cos-sts":"^3.1.3"
  }
}

这里的 qcloud-cos-sts 是COS封装的SDK库。

本地运行包安装,后续可以上传到云函数。

javascript 复制代码
npm install

这里注意本地nodejs的版本,后续云函数使用18.15,本地也最好使用同样的版本来构建。

命令运行后,本地将生成 node_modules,此时本地环境已准备好,接下来准备搭建云函数。

4.3、部署到SCF云函数

接下来把上述代码部署到云函数。

1、开通云函数

地址:https://console.cloud.tencent.com/scf/index

2、新建函数

地址:https://console.cloud.tencent.com/scf/list

选择 函数服务 - 新建:

这里配置函数:

  • 从头开始 - 这里选择从头开始,纯手搓;
  • 函数类型 - 默认是事件函数,对于目前的场景,也可以直接选择Web函数,都可以满足;
  • 函数名称 - 友好名字,这里我们起名 getCosToken,自己好理解的就可以;
  • 运行环境 - 使用自己熟悉的语言即可,这里选择 nodejs 18.15;
  • 提交方法 - 这里初次使用可以选择"本地上传zip包",按照 5.3 步骤,本地开发好后直接上传压缩包,当然也可以选择"在线编辑";

勾选协议后,点击"完成",即创建了新的云函数。

从函数列表查看:

此时的云函数已经准备就绪,那么如何触发呢?也就是如何给我们的前端页面来进行调用呢?这就需要用到"函数URL"(对于Web函数类型的云函数,类似,可以尝试下,后续也补充一下)。

3、开通公网访问

在上面的函数列表点击函数名,进入函数管理页面:

点击"函数URL",点击"新建函数URL":

然后设置函数配置:

这里的大部分配置都和HTTP的请求方式是一样的,所以可以按照自己需求来定制配置,上述配置是可以满足任意请求,所以,因为为了测试。

配置完成的样子:

此时可以通过这里的公网访问地址来访问云函数,可以用postman等工具来测试下,因为这里支持所有请求方式,包括get请求,所以可以直接用浏览器测试下。

4、自定义域名

我们上面开通的函数URL是一串很长的地址,这里给他设置一个友好域名地址。

自定义域名地址:https://console.cloud.tencent.com/scf/domain

选择 自定义域名 - 添加自定义域名,

这里主要注意下"路径映射"。路径是域名访问的地址,函数是对应的云函数,可以同事映射配置多个云函数。

如上图,表示访问域名任意一个地址都可以访问云函数 getCosToken。一般建议每个云函数对应一个具体的地址,这样为了演示使用了 /* 表示任意路径访问,都会访问到 getCosToken 云函数。

到这里,我们的云函数环境已准备好。

五、完善云函数

在实际开发中,每一个环节不是独立串行的,往往是迭代且交错进行。

在完成上述开发云函数后,我们就可以在前端页面调用云函数来确保流程的通顺,只是云函数的逻辑是mock的,这里开始实际获取openid和cos的临时密钥。

5.1、获取微信用户的openid

每个用户上传的文件都保存在自己的路径下,需要使用用户的标识来区分。最容易想到的是openid,也考虑过手机号,但是:

好了,还是使用openid。

5.1.1、获取openid的代码
javascript 复制代码
async function getOpenId(code) {
  const wxAppId = 'wx12345'
  const wxSecret = 'abcdefg'
  const url = `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${wxAppId}&secret=${wxSecret}&code=${code}&grant_type=authorization_code`;
  const wxRes = await request(url);
  if (wxRes.errcode) {
    return {
      statusCode: 400,
      data: wxRes.errmsg + ', code:' + code,
    };
  }
  return {
    statusCode: 200,
    data: wxRes.openid
  };
}

这里的wxAppId和wxSecret是微信开发信息,获取的方式也有两种选择,一种是使用免费的测试号,一种是使用认证的服务号。

5.1.2、方案1 - 测试号

如果临时使用,可以使用测试号,完全免费。

测试号地址:https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index

这里两部分信息:

测试号信息 - 就是我们需要的 wxAppId和wxSecret。

JS接口安全域名 - 前面4.3.2配置的CDN静态网站的域名(site.xxxxx.com)。这样可以通过网站来访问。

5.1.3、方案2 - 认证的服务号

如果有米,或者公司使用,那就需要使用认证的服务号。获取开发所需要的信息也有两个地方。

1、从服务号获取

登录服务号:https://mp.weixin.qq.com/

选择 设置与开发 - 开发接口管理 - 基础配置,可以看到开发信息。

JS接口安全域名和网页授权域名设置:

选择 设置与开发 - 账号设置 - 功能设置,可以查看和设置域名。

2、从微信开发者平台获取

地址:https://developers.weixin.qq.com/console/index

选择 我的业务 - 服务号,

在右侧选择对应的服务号,然后在"基础信息"中可以查看对应的信息。

5.2、获取对象存储COS的临时密钥

由于访问对象存储需要密钥,考虑到安全,用正式密钥生成临时密钥,发布到前端页面,然后在前端用临时密钥来访问COS。临时密钥有时效限制,能够一定程度保障安全。

使用临时密钥访问COS:

https://cloud.tencent.com/document/product/436/68283

获取临时密钥的接口文档:

https://cloud.tencent.com/document/product/436/14048

获取临时密钥的调试工具:

https://console.cloud.tencent.com/api/explorer?Product=sts&Version=2018-08-13&Action=GetFederationToken

5.2.1、获取COS临时密钥的代码
javascript 复制代码
async function getCosAuth(openId) {
  const bucketName = 'upload-1234567';
  var appId = bucketName.substr(1 + bucketName.lastIndexOf('-'));
  var policy = {
    'version': '2.0',
    'statement': [{
      'action': [
        // 简单上传
        'name/cos:PutObject',
        'name/cos:PostObject',
        // 获取文件
        'name/cos:GetObject',
        'name/cos:GetBucket',
        // 分片上传
        'name/cos:InitiateMultipartUpload',
        'name/cos:ListMultipartUploads',
        'name/cos:ListParts',
        'name/cos:UploadPart',
        'name/cos:CompleteMultipartUpload',
        // 简单上传和分片,需要以上权限,其他权限列表请看 https://cloud.tencent.com/document/product/436/31923
      ],
      'effect': 'allow',
      'principal': { 'qcs': ['*'] },
      'resource': [
        'qcs::cos:' + config.region + ':uid/' + appId + ':' + config.bucket + '/' + openId + '/*',
      ],
    }],
  };
  
  return await STS.getCredential({
    secretId: config.secretId,
    secretKey: config.secretKey,
    proxy: config.proxy,
    durationSeconds: config.durationSeconds,
    region: config.region,
    endpoint: config.endpoint,
    policy: policy,
  });
}

这里的bucketName对应的是upload存储桶的名称 - "upload-123456"。

到这里,我们的云函数功能基本完成。

六、前端页面

到这里,我们整理下(实在是这篇文太长了):

  • 我们有了一个网站,https://site.xxxxx.com
  • 我们有了存储桶,可以存放上传的图片和视频;
  • 我们已经准备好了云函数,它负责跟各种服务沟通,返回我们所需要的授权和信息;

接下来重构前端页面,来实际调用COS的相关功能。

6.1、COS入门指南

SDK概览:

https://cloud.tencent.com/document/product/436/6474

SDK下载地址:

https://github.com/tencentyun/cos-js-sdk-v5/blob/master/dist/cos-js-sdk-v5.min.js

快速入门:

https://cloud.tencent.com/document/product/436/11459

自主诊断工具:

https://console.cloud.tencent.com/cos/diagnose

6.2、前端页面逻辑

1、初始化COS

有两种 获取临时密钥进行初始化的方式,如下:

javascript 复制代码
import COS from 'cos-js-sdk-v5';
const cos = new COS({
    getAuthorization: async function (options, callback) {
      const data = await fetchSts('xxxx'); // 需自行实现获取临时密钥逻辑
      callback({
        TmpSecretId: data.credentials.tmpSecretId,
        TmpSecretKey: data.credentials.tmpSecretKey,
        SecurityToken: data.credentials.sessionToken,
        // 建议返回服务器时间作为签名的开始时间,避免客户端本地时间偏差过大导致签名错误
        StartTime: data.startTime, // 时间戳,单位秒,如:1580000000
        ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000000
        ScopeLimit: true, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用
      });
    }
});
javascript 复制代码
import COS from 'cos-js-sdk-v5';
const cos = new COS({
    // 其他配置项可参考下方 初始化配置项
    // getAuthorization 必选参数
    getAuthorization: function (options, callback) {
        // 初始化时不会调用,只有调用 cos 方法(例如 cos.putObject)时才会进入
        // 异步获取临时密钥
        // 服务端 JS 示例:https://github.com/tencentyun/cos-js-sdk-v5/blob/master/server/
        // 服务端其他语言参考 COS STS SDK :https://github.com/tencentyun/qcloud-cos-sts-sdk
        // STS 详细文档指引看:https://cloud.tencent.com/document/product/436/14048
        const stsUrl = 'http://example.com/server/sts'; // stsUrl 替换成您自己的后端服务
        fetch(stsUrl)
          .then(response => response.json())
          .then(data => {
            if (!data || !data.credentials) {
              return console.error('credentials invalid:\n' + JSON.stringify(data, null, 2))
            }
            // 检查credentials格式
            const { credentials } = data;
            console.log(credentials);
            callback({
              TmpSecretId: credentials.tmpSecretId,
              TmpSecretKey: credentials.tmpSecretKey,
              SecurityToken: credentials.sessionToken,
              // 建议返回服务器时间作为签名的开始时间,避免客户端本地时间偏差过大导致签名错误
              StartTime: data.startTime, // 时间戳,单位秒,如:1580000000
              ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000000
              ScopeLimit: true, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用
            });
          })
          .catch(error => {
            console.error('获取临时密钥失败', error);
          });
    }
});
export default cos;
2、上传

sdk: https://cloud.tencent.com/document/product/436/64960

api: https://cloud.tencent.com/document/product/436/7749

javascript 复制代码
cos.putObject({
	Bucket: bucket,
	Region: region,
	Key,
	Body: file,
	Headers: {
	  'x-cos-acl': 'public-read'
	},
	onProgress: function (info) {
	  // ...
	}
}, function (err, data) {
	if (err) {
	  // 失败
	} else {
	  // 成功
	}
});
3、查看

sdk: https://cloud.tencent.com/document/product/436/64962

api: https://cloud.tencent.com/document/product/436/7734

javascript 复制代码
    cos.getBucket({
      Bucket: bucket,
      Region: region,
      Prefix: `${openid}`
    }, function (err, data) {
      if (err) {
        console.log('获取文件列表失败');
        return;
      }

      // 过滤掉 Size 为 0 的对象
      const contents = (data.Contents || []).filter(item => Number(item.Size) > 0);

      if (contents.length === 0) {
        console.log('暂无上传文件');
        return;
      }

      // 按时间倒序排列
      allFiles = contents.sort((a, b) =>
        new Date(b.LastModified) - new Date(a.LastModified)
      );

      // 显示
      display(allFiles);
    });
  }

七、优化

7.1、上传视频优化

7.1.1、需求分析

上传的某些视频,在页面不能预览,求助一下AI:

这里我们就需要使用腾讯云的"任务与工作流",进行转码后存储。

7.1.2、视频转码的任务与工作流

进入COS存储桶 upload-123456:

选择 任务与工作流 - 工作流管理 - 创建工作流,

点击工作流节点的 + 号,选择 媒体处理 - 音视频转码,

这里按照需要配置:

  • 目标存储桶 - 选择 upload-123456;
  • 目标文件名 - 转码后生成的文件名,这里是 {inputName}_{RunId}.{ext},原始文件名为 demo.mp4,会生成比如 demo_1234.mp4 的转码的文件。可以配置自己的规则,比如 {inputName}_fix.${ext},这样会生成 demo_fix.mp4,方便程序处理;
  • 目标路径 - 转码后的保存路径,可以放在不同路径,方便查询获取,当然也可以保存在原始路径 ${inputPath};
  • 转码模板 - 这里就是转码的核心地方,选择具体的转码格式,务必选择H.264视频编码 + AAC音频编码,这是浏览器原生支持的黄金组合,这里选择 H264-MP4-2K。

配置好后点击确定后返回,并保存,返回工作流列表:

这里点击 "上传触发执行",这样在存储桶有视频文件上传时,就会自动进行转码。

7.2、H5页面生成二维码图片

7.2.1、需求分析

直接发链接感觉有点low,发个图片在群里,让大家扫码跳转吧。

7.2.2、草料二维码

随便搜一个,这是AI推荐的第一个,所以借用一下。

官网地址:https://cli.im/url

还可以点击上图中右方的"二维码美化":

点击上方的"更换样式",有更多花样:

选择喜欢的样式:

可以调整文字颜色等,确认ok后,点击"下载打印"即可。

好了,终于结束了,感觉可以出一个长视频了💤

相关推荐
llq_3505 小时前
如何用 GitHub Pages 完成企业微信的域名归属认证?(适合没有服务器的开发者)
微信
今天也在研究公众号1 天前
Apple同款SVG,怎么写出来?手写+编辑器,两张方法都能搞定!
微信
阿里云云原生2 天前
大模型成本太高?阿里云Serverless AI原生架构,教你极致省钱又稳健部署!
serverless
开发加微信:hedian1163 天前
短剧小程序开发全攻略:技术选型与实现思路
微信·小程序·架构·aigc·交互
AiXed4 天前
PC微信协议之nid算法
python·网络协议·算法·微信
sg_knight4 天前
微信小程序中 WebView 组件的使用与应用场景
前端·javascript·微信·微信小程序·小程序·web·weapp
阿里云云原生5 天前
阿里云 FunctionAI 技术详解:基于 Serverless 的企业级 AI 原生应用基础设施构建
人工智能·阿里云·serverless