在小程序开发就是带着脚镣跳舞。平时用习惯了 activestorage, 今日想在小程序上上传照片也接入 active storage,发现还是有一些有意思。
之所以使用 direct upload 原因很简单:不花服务器带宽,增加体验。那么传统的 direct upload 需要几步呢?
active storage 的 direct upload 上传的步骤
/rails/active_storage/direct_uploads
拿到 传输的 blob 信息那么就在小程序中一一解决这些问题就好了
小程序无法操作 window 对象以及使用标准的 File 对象,所以,无法直接使用 activestorage npm 包,拿到图片的大小,type,filename 咱瞎编一个,都好办,难点在于 checksum.
checksum 本来是在file_checksum.js中得出的,原理大概是 用 spark-md5 读出文件的 md5, 再 base64 下 MD5,得到最终的 checksum。
小程序中有一个 wx.getFileInfo, 可以拿到 文件 的 md5 值,这样就不用使用标准 File 读文件算 md5,但是因为小程序没有 window.btoa 方法,那么实现这个方法即可,后来发现 npm 包 crypto-js
即可实现
默认情况下,小程序没打开 npm 构建,需要操作一下
在小程序根目录执行 npm init, 之后再在微信开发程序面板右侧点击详情,在本地设置里打开“使用 npm 模块”,之后执行 yarn add cryto-js
,最后在微信开发程序的菜单栏里选择 工具,构建 npm,这样就可以 import 了
const fileInfo = await wx.getFileInfo({
filePath: file.path,
})
const checksum = crypto.enc.Base64.stringify(crypto.enc.Hex.parse(fileInfo.digest));
至于 content type,则在 wx.getImageInfo 返回值里的 type 体现,比如 jpg 比如 png,需要自行拼接一下
const info = await wx.getImageInfo({
src: file.path
})
至此,最麻烦的步骤一 checked
这里比较简单,主要需要解决的是 csrf 的问题,我是为了自己以后扩展方便,重新继承了之前的 direct_upload controller, 顺便跳过了 csrf
class Api::V1::DirectUploadsController < ActiveStorage::DirectUploadsController
# Should only allow null_session in API context, so request is JSON format
protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' }
# Also, since authenticity verification by cookie is disabled, you should implement you own logic :
before_action :verify_user
private
def verify_user
.....授权
end
end
步骤 2 checked
这里有个小程序的坑,小程序官方提供的 uploadFile 是确定了 method 必须为 post 和 data 格式,由于我的项目使用了 阿里云的 oss 存储,是用的 put 方法,所以没办法直接用 uploadFile,而是要靠 wx.request 来解决问题了
其实也不难,从 blob 返回拿好数据后,将 file 打到 body 中即可。那么如何将 file 打到 body 呢?需要使用 wx.getFileSystemManager().readFile
他的结果里包含了 file 的内容,具体代码为
wx.getFileSystemManager().readFile({
filePath: file.path,
success: (e) => {
wx.request({
url: resp.data.direct_upload.url,
method: 'put',
header: resp.data.direct_upload.headers,
data: e.data,
success: (xxx) => {console.log(xxx)}
});
}
})
至此,上传文件 ok
这个没啥 正常 request 处理即可
至此,整个流程都可以跑通了。
难点在于 计算 checksum 和 解决 put 文件问题,解决了这些,就问题不大了。希望对开发小程序的朋友有所帮助。