本文主要涉及两个概念:

  • 阿里云OSS:对象存储(Object Storage Service,简称OSS),是阿里云对外提供的海量、安全和高可靠的云存储服务。
  • bootstrap-fileinput:An enhanced HTML 5 file input for Bootstrap 3.x with file preview for various files, offers multiple selection, and more.

客服称OSS不限制上下行流量,而且不占用ECS带宽,所以将静态文件存放在OSS是个不错的选择。除了放置站点引用的资源文件外,主要用于用户文件的上传。阿里云提供了Web端直传方式,文件不经过站点服务器,不影响站点的性能和带宽。真正撸代码时,遇到了不少坑,而官方文档秉承阿里一贯的程序员风格,天马行空毫不连贯,博主东拼西凑才理顺各细节,关键点记录如下,供需要的朋友参考。


阿里官方没有提供.NET的demo,找到Post Object,该文档描述了提交的各参数。进行Post操作要求对bucket有写权限,如果bucket为public-read-write,可以不上传签名信息,否则要求对该操作进行签名验证。与Put操作不同,Post操作使用AccessKeySecret对policy进行签名计算出签名字符串作为Signature表单域的值,OSS会验证该值从而判断签名的合法性(不需要遵循用户签名验证(Authentication)的规定,另外在header或url中加上签名)。policy又是啥呢?Post请求的policy表单域用于验证请求的合法性。 policy为一段经过UTF-8和base64编码的JSON文本,声明了Post请求必须满足的条件(文件大小、一些http头等,还有该条件的过期时间)。虽然对于public-read-write的bucket上传时,post表单域为可选项(其它情况,因为需要签名验证,所以是必选项),也强烈建议使用该域来限制Post请求。

so,第一步,构造Post条件,对于不同bucket,可以有不同的条件,可以写在web.config中,如果经常变动,也可以写在数据库中方便管理。

然后,给前端提供一个获取policy的接口,代码就不贴了,使用官方提供的SDK,很简单。这里假设接口名称为GetPolicyForOSSUpload,返回结果是:

Data = new ModelForOSSUpload
{
AccessKeyId = aliyunconfig.AccessKeyId,
PolicyBase64 = encodedPolicy,
Signature = signature,
Expiration = expiration
}

注意,expiration已经被用于构造PolicyBase64了,这里又单独给个字段返回,是给前端用的,在有效时间内,不用再调该接口,能减轻服务器压力一点是一点。

前端js是这样的:

 _getUploadPreSetting: function (bucketKey, policyName) {
var presetting = {}, error = {}, self = this;
var inner_getUploadPreSetting = function () {
var now = new Date();
if (!presetting.Expiration || presetting.Expiration < now) {
presetting = {};
error = {};
$.ajax({
url: self._ossOpts.uploadPreSettingUrl,
type: 'GET',
async: false,
data: { bucketKey: bucketKey, policyName: policyName },
success: function (result) {
if (result.IsSucceed) {
presetting = result.Data;
//应付/Date(1460817323032)/这种奇葩格式
presetting.Expiration = eval('new ' + (presetting.Expiration.replace(/\//g, '')));
}
else {
error = result;
}
},
error: function (xhr, msg) {
error = { IsSucceed: false, Message: msg };
}
});
}
return presetting || error;
};
return inner_getUploadPreSetting;
}

此处用了闭包,这是因为不同的policy,我们以bucketKey和policyName进行区分(看贴出来的web.config片段),如果一个页面需要多个policy,每个policy都要对应一个变量,数量不定的情况下,我们也不能硬编码,同时为了让它们互不影响,就采用了闭包的方式。调用如下:

var getUploadPreSetting = this._getUploadPreSetting(this._ossOpts.bucketKey, this._ossOpts.policyName);
var presetting = getUploadPreSetting();

policy的部分到此为止,下面我们来看下bootstrap-fileinput这个组件,并对它进行一点点改造,以便于符合OSS的上传规则。


除了文件数据,提交时还要附加OSS要求的一些表单域,比如刚才讲的policy、Signature,还可以给每个文件加上cache-Control、callback(上传成功后,OSS回调我们的接口地址)等。我们在初始化bootstrap-fileinput(下称fileinput)时可以传入一个uploadExtraData配置项(函数或对象),在上传每个文件时,fileinput会调用uploadExtraData,将获取到的数据附加到文件数据后一起上传。然而这就存在一个问题了,OSS文档中说“文件或文本内容,必须是表单中的最后一个域。”,否则会返回“The bucket POST must contain the specified 'key'. If it is specified, please check the order of the fields”的错误信息。

题外话:关于表单域顺序的说明,以前文档中并没有,还是博主在一次工单提交和差点投诉后才加上去的,当时很奇怪难道没人遇到过,还是说这样用OSS的人不多?另外在和客服扯皮的同时,博主也上网搜了一把,发现AWS的用户竟然也遇到类似问题,请看 InvalidArgumentBucket POST must contain a field named 'key'. If it is specified, please check the order of the fields.keyB,连返回的错误消息都大同小异,博主大胆猜测,阿里云和AWS的数据存储用的是同一套组件,还是开源的,博主知识浅陋,有知道的朋友说一声。

于是只能去看fileinput的源码了,幸好它是开源的,我们只需要改动一下_uploadSingle函数的末尾:

self._uploadExtra(previewId, i); //新加
formdata.append(self.uploadFileAttr, files[i], self.filenames[i]); //文件数据
formdata.append('file_id', i);
self._ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError, previewId, i, true); //也要改造下_ajaxSubmit,传入true表示额外数据不再附加

_ajaxSubmit也改造了下,圆圈内为新加:

fileinput改造完毕,so easy!那么当上传成功后,我们一般都是要对应用数据做一些处理,比如更新数据库中的url地址什么的,我们可以获取响应信息,然后再调用相应的后台接口,OSS也提供了直接回调的方式,后者能传递更多关于文件的信息,并且在构造callback时可自定义参数,因此更灵活,方便后台回调接口的数据处理,具体可看Callback


下例,前端js:

callback:{
"callbackUrl":GlobalConfig.siteurl+'Merchandise/SetMerchandisePicUrl',
"callbackBody":"merchandiseid="+vm.merchandise.BasicInfo.ID+"&picname=${object}"
}

后端回调接口:

 [AllowAnonymous]
public async Task<ActionResult> SetMerchandisePicUrl(int merchandiseid, string picname)
{
var aliyunconfig = MvcApplication.AliyunConfig;
var bucket = aliyunconfig.OSS.Buckets["merchandise_pictures"];
var picUri = $"http://{ bucket.Value}.{aliyunconfig.OSS.ImgEndpoint}/{picname}";
await MerchandiseContext.AppendPicUri(merchandiseid, picUri);
return this.Json(new
{
initialPreview = new string[] { picUri },
initialPreviewConfig = new List<object> {
new {
caption = picname,
//width ="160px", //并没有什么用
url =Url.Action("RemoveMerchandisePicUrl"),
extra = new {picUri= picUri,merchandiseid = merchandiseid}
}
}
});
}

接口允许匿名,便于OSS调用,为了防止恶意调用,最好进行签名校验。fileinput根据返回结果判断是否上传成功(没有error属性表示上传成功),若成功且结果里有initialPreview[和initialPreviewConfig]等属性,则将这些属性应用到对应文件显示。特别注意initialPreviewConfig中的url和extra属性,表示删除该文件时调用的接口和传递的参数。

另外,若我们不指定回掉地址,那么OSS默认会返回空文档(在上传成功的情况下),若需要让其返回官方文档中提到的PostResponse,需要指定success_action_status为201。


其它参考资料:

理解DOMString、Document、FormData、Blob、File、ArrayBuffer数据类型

Web 前沿——HTML5 Form Data 对象的使用

转载请注明本文出处:http://www.cnblogs.com/newton/p/6066020.html

Upload files to aliyunOSS with bootstrap-fileinput的更多相关文章

  1. 结合bootstrap fileinput插件和Bootstrap-table表格插件,实现文件上传、预览、提交的导入Excel数据操作流程

    1.bootstrap-fileinpu的简单介绍 在前面的随笔,我介绍了Bootstrap-table表格插件的具体项目应用过程,本篇随笔介绍另外一个Bootstrap FieInput插件的使用, ...

  2. bootstrap fileinput 使用记录

    第一次使用bootstrap fileinput碰到了许多坑,做下记录 需求 本次使用bootstrap fileinput文件上传组件,主要用来上传和预览图片.作为一个后台管理功能,为某个表的某个字 ...

  3. Bootstrap fileinput.js,最好用的文件上传组件

    本篇介绍如何使用bootstrap fileinput.js(最好用的文件上传组件)来进行图片的展示,上传,包括springMVC后端文件保存. 一.demo   二.插件引入 <link ty ...

  4. JS文件上传神器bootstrap fileinput详解

    Bootstrap FileInput插件功能如此强大,完全没有理由不去使用,但是国内很少能找到本插件完整的使用方法,于是本人去其官网翻译了一下英文说明文档放在这里供英文不好的同学勉强查阅.另外附上一 ...

  5. ***Bootstrap FileInput插件的使用经验汇总

    插件下载地址: https://github.com/kartik-v/bootstrap-fileinput/ 官方DEMO查看: http://plugins.krajee.com/file-ba ...

  6. bootstrap fileinput插件使用感悟

    bootstrap fileinput 的填坑感悟              这个插件在demo的网站地址http://plugins.krajee.com/file-preview-icons-de ...

  7. Bootstrap FileInput中文API整理

    这段时间做项目用到bootstrap fileinput插件上传文件,在用的过程中,网上能查到的api都不是很全,所以想着整理一份比较详细的文档,方便自己今后使用,也希望能给大家带来帮助,如有错误,希 ...

  8. Bootstrap FileInput中文API文档

    Bootstrap FileInput中文API整理 这段时间做项目用到bootstrap fileinput插件上传文件,在用的过程中,网上能查到的api都不是很全,所以想着整理一份比较详细的文档, ...

  9. bootstrap fileinput +springmvc图片上传-krajee

    引入的文件 <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-fileinput/4.4.9/css/filei ...

随机推荐

  1. Kali Linux additional tools setup

    The steps are pretty straight forward. The only tool that might cause some confusion is SMBexec. Thi ...

  2. Linux测试环境部署jdk(一)

    安装配置JDK yum install -y lrzsz  安装rz,方便xshell上传下载文件 Jdk: jdk-6u1-linux-i586 Tomcat: apache-tomcat-7.0. ...

  3. Monkey工具使用详解

    上节中介绍了Monkey工具使用环境的搭建,传送门..本节我将详细介绍Monkey工具的使用. 一.Monkey测试简介 Monkey测试是Android平台自动化的一种手段,通过Monkey程序模拟 ...

  4. 使用 Fluent API 配置/映射属性和类型(摘自微软Data Access and Storage)

    使用 Fluent API 配置/映射属性和类型 使用实体框架 Code First 时,默认行为是使用一组 EF 中内嵌的约定将 POCO 类映射到表.但是,有时您无法或不想遵守这些约定,需要将实体 ...

  5. Nginx-解读内置非默认模块 ngx_http_stub_status_module

    1.Background ngx_http_stub_status_module 是一个 Nginx 的内置 HTTP 模块,该模块可以提供 Nginx 的状态信息.默认情况下这个模块是不被编译进来的 ...

  6. 跨域请求解决方法(JSONP, CORS)

    1.跨域 假设我们页面或者应用部署在 http://www.aaa.com 上了,而我们打算从 http://www.bbb.com 请求提取数据.一般情况下,如果我们直接使用 AJAX 来请求将会失 ...

  7. 在实现和使用上与select和poll有很大差异

    在看此课程的读者,希望先阅读关于函数基础内容 函数定义与函数作用域 的章节,因为此课程或多或少会涉及函数基础的内容,而基础内容,本人放在 函数定义函数作用域 章节. 本文直接赘述函数参数与闭包,若涉及 ...

  8. centos6.5 升级安装pcre 8.39版本

    1.查看系统pcre安装情况 rpm -qa pcre 2.卸载系统自带的旧版本 rpm -e --nodeps pcre 3.下载新版安装 地址:ftp://ftp.csx.cam.ac.uk/pu ...

  9. [转]windows下编译及使用libevent

    http://www.cnblogs.com/luxiaoxun/p/3603399.html Libevent官网:http://libevent.org/ windows 7下编译: 编译环境:  ...

  10. EMC起步:华为交换机拆解

    [作者:byeyear    Email:east3@163.com    转载请保留此行] 1. 静电抗扰 理想情况下,我们的系统是一个中空且密闭的金属盒子,根据电磁场理论,外界的任何静电源都不可能 ...