腾讯云COS对象存储预签名普通上传方式使用记录


因自己有七牛云换腾讯云的冲动,毕竟重新绑身份证正反面我是有些抗拒的,So?自己动手丰衣足食,其实这里也没什么好说的,毕竟别人文档写得那么全了,但是觉得还是做下步骤记录。

腾讯云COS服务器java端SDK目前版本为V5。

需求:像七牛云一样,从服务器获取签名后从移动端上传文件,即不需要在移动端配置id与密匙,直接根据签名上传。

区别:七牛需要在移动端与服务端各自依赖七牛云SDK,腾讯云COS只需要在服务端依赖SDK,但是很明显,腾讯云在移动端要做的操作就会多些,毕竟没有SDK。

注意:这里忽略掉腾讯云各自单独配置SDK的情况,即每个平台独立配置id与密匙完成操作。这些在官方文档上可以很轻松的学习到。

本文与腾讯云java服务端SDK有关:

官方快速入门文档:https://cloud.tencent.com/document/product/436/10199

官方API文档:https://cloud.tencent.com/document/product/436/12263

生成预签名链接

服务端采用SpringBoot或者SpringMVC均可,请随意发挥你的才能。

@RequestMapping(value = {"/getCOSUploadToken"}, method = {RequestMethod.POST})
@ResponseBody
public BaseResp<String> getCosUploadToken(@Param("fileName") String fileName) {
    String secretId = "your accessKey";
    String secretKey = "your secretKey";

    // bucket的命名规则为{name}-{appid} ,此处填写的存储桶名称必须为此格式
    String bucketName = "buketName-Appid";

    // 1 初始化用户身份信息(secretId, secretKey)
    COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
    // 2 设置bucket的区域, COS地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
    ClientConfig clientConfig = new ClientConfig(new Region("your region"));
    // 3 生成cos客户端
    COSClient cosclient = new COSClient(cred, clientConfig);

    //设置过期时间 3分钟
    Date expiredTime = new Date(System.currentTimeMillis() + 180L * 1000L);

    // 要签名的 key, 生成的签名只能用于对应此 key 的上传 这里路径拼接为上传至COS的head文件夹中
    String key = "/head/"+fileName;

    URL sign = cosclient.generatePresignedUrl(bucketName, key, expiredTime, HttpMethodName.PUT);

    System.out.println(sign);

    BaseResp resp = new BaseResp();
    resp.setStatus(0);
    resp.setMessage("");
    resp.setData(sign);

    return resp;
}

生成预签名服务端就这么点内容,简单解释下,这里面需要填写的内容有:secretId、secretKey、bucketName、Region、前两个参数可以在你的云API密匙找到,bucketName即你需要使用的桶名,但是这里有一个要求就是需要在你的桶名后跟上-AppId,当然如果你的桶命名已经是{name}-{appid},则无需重复添加appid,appid也可以在“云API密匙中找到”,从上面代码可已看到该请求会携带一个参数fileName,为什么需要这样?因为签名一次只能对一个key进行签名,也就是对一个文件路径签名,如果你写死,则每次都会覆盖。

这里的策略是从移动端每次发送需要上传的文件名来进行签名,避免不同的文件会被覆盖。最后返回签名过的链接,注意:预签名完成返回的链接是完整的,即“http://xxxxxxxx.myqcloud.com/你的key?sigin=一串签名”

这个链接可以直接使用HTTP的PUT请求方式上传文件。

移动端使用:

首先你得获取到你想要上传的文件以及签名后的链接。这里使用Okhttp与RxJava结合的方式,方便切换线程和回调等

/**
 * 腾讯云COS预签名工具类
 */class UploadUtils {

    /**
     * uploadUrl put请求地址 也就是上面服务端返回的签名后的链接
     * localPath 本地文件路径 你需要上传的文件路径 绝对路径 完整的
     */    fun put(uploadUrl: String, localPath: String): Observable<String> {
        //请求内容类型
        val imageType = MediaType.parse("image/jpeg; charset=utf-8")

        //获取文件名
        val name = localPath.substring(localPath.lastIndexOf("/")+1, localPath.length)

        val file = File(localPath)
        val body = RequestBody.create(imageType, file)
       //创建request
        val request = Request.Builder()
                .url(uploadUrl)
                .put(body) //PUT方式
                .build()

        return Observable.create<String> {
            //设置各种Timeout 然后执行,该部分代码为异步,我在使用时调用了subscribeOn(Schedulers.io())
            val response = OkHttpClient.Builder()
                    .connectTimeout(600, TimeUnit.SECONDS)
                    .readTimeout(200, TimeUnit.SECONDS)
                    .writeTimeout(600, TimeUnit.SECONDS)
                    .build()
                    .newCall(request)
                    .execute()
            //这里的response是没有返回内容的,也就是说,上传后并不会直接给你远程链接,但是code会有,可以判断是否成功

            //拼接上传至COS后的远程链接
            val link = "${QCLOUD_SERVER_ADDRESS}head/$name"
            it.onNext(link)
        }
    }
}

这里说下流程,就是使用PUT请求的方式,将文件通过服务器签名的链接上传即可,但是注意需要最后自己拼接远程链接。拼接方法,在你的对象存储中随便上传一个文件,然后点击文件信息,将类似域名“http://你的bucket名-你的appid.你的存储地区.myqcloud.com/”作为baseUrl也就是我上面的QCLOUD_SERVER_ADDRESS,然后拼上你在服务器端配置的key,我这里也是head文件夹+文件名。

调用时:

UploadUtils().put(result, mLocalFileUrl).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
        .subscribe(object : Observer<String> {
            override fun onComplete() {}

            override fun onSubscribe(d: Disposable) {}

            override fun onNext(t: String) {
                mRemoteFileUrl = t
                //做你要做的 比如我这里是将其加载到某个控件
                GlideUtils.loadUrlImage(this@UserInfoActivity, mRemoteFileUrl, mUserIconIv)
            }

            override fun onError(e: Throwable) {e.printStackTrace()}
        })

以上,为所有的生成预签名方式以及简单上传使用内容。

生成签名(有问题)

生成签名与生成预签名区别在哪呢?区别在生成预签名会生成完整链接,而生成签名则只会生成后面sign=xxxx的那一串签名。且签名需要配合移动端SDK进行使用。根据文档描述来看,应该是需要接入CAM系统进行使用,这里未测试。

易用性和文档上来讲七牛毫无疑问更胜一筹,但是移动端想精简一些,可考虑腾讯云。

声明:TIL|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA[ZH]协议进行授权

转载:转载请注明原文链接 - 腾讯云COS对象存储预签名普通上传方式使用记录


Life is very interesting. In the end, some of your greatest pains become your greatest strengths.