Ajax直传文件到Azure Storage的Blob服务中

(此小说同时公布在本人微信公众号“dotNET每一天精华小说”,欢迎右侧二维码来关怀。)

题记:为了庆祝得到微信公众号赞美效用,忙里抽闲分享一下以来干活的某些经验:怎么着直接从浏览器中上传文书到Azure
Storage的Blob服务中。

为什么

如若你的Web应用程序利用了云存储(比如Azure
Storage)来存储用户的资源文件(比如图片、摄像等等)。平常的做法,是用户访问你的Web前端,上传文件到你的Web后端应用,然后在后端程序中选用云存储的SDK把公文再转传到云存储中。架构如下图所示:

Ajax 1

那种情势下,即使简易方便。不过,由于上传文件的历程,需求以Web后端程序当做代理,假使上传文件巨大反复,会给后端程序的托管服务或托管服务器造成较小运算压力和流量压力。所以,还有一种形式,是让用户一向在浏览器中把公文上传给云存储服务。我所熟练的云平台(Azure
,AWS,Aliyun)都提供了近乎的性状,只是完成形式或名称上有所不一致。此外,在那种措施下,为了有限支撑安全性,一般不会直接把云存储的造访Key暴光给Web前端,所以都会提供一种折中艺术,让你可以生成限时失效权限有限的共享访问Key,把那几个共享Key给到前端来收获访问能力。在Azure中,这几个特性称之为共享访问签章(Shared
Access Signatures,SAS),而全方位架构就成为上面那样:

Ajax 2

在这一个架构中,你先从后端服务器得到SAS Url,然后径直上传文件给Azure
Storage,上传文件成功后,借使要求再把一部分文件元数据传递给后端服务器(其实Azure的文件也可以附加保存元数据的,你协调都得以不保存元数据)。其实那种架构不仅能够运用于文件存储服务,在Azure中还足以在前者直接访问Azure
Storage Table、Queue等劳务。关于SAS模型,微软官方的文档《Shared Access
Signatures, Part 1: Understanding the SAS
Model》(http://t.cn/R4OQona)讲的很精晓,上边的图就是引自那篇小说。

本来,在成千成万时候,大家是急需混用那二种情势的,在急需更加多安全控制和流量可控的情况,使用代理转传方式;在黑河可隔离流量不可控的情事下,使用直传方式。我自己的实践当中,也是二种格局混用,在须要用户上传文件到集体存储账号的时候,使用代理情势,在用户上传文件到用户独有存储账号的时候,使用直传形式。

鉴于自家当下拔取的云平台是Azure,所以下边演示的代码也是基于Azure Storage
SDK的。

赢得SAS访问地址

根据Azure的文档《Shared Access Signatures, Part 2: Create and use a SAS
with Blob
storage》(http://t.cn/R4OQeBd)所述,获取SAS其实也相当简单。

率先实例化CloudStorageAccount、CloudBlobClient和CloudBlobContainer,如下:

//Parse the connection string and return a reference to the storage account.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));

//Create the blob client object.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

//Get a reference to a container to use for the sample code, and create it if it does not exist.
CloudBlobContainer container = blobClient.GetContainerReference("sascontainer");
container.CreateIfNotExists();

接下来创制一个临时的策略,调用CloudBlobContainer的GetSharedAccessSignature方法来变化访问token,如下:

//Set the expiry time and permissions for the container.
//In this case no start time is specified, so the shared access signature becomes valid immediately.
SharedAccessBlobPolicy sasConstraints = new SharedAccessBlobPolicy();
sasConstraints.SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24);
sasConstraints.Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.List;

//Generate the shared access signature on the container, setting the constraints directly on the signature.
string sasContainerToken = container.GetSharedAccessSignature(sasConstraints);

所生成的token实际就是一个包括有多少个政策规则的询问字符串,然后把那几个token通过Web后端的一个Api调用(当然是讲明用户权限后)传递给Web前端。前端为要上传的文书构造那样一个Url:存储容器的Uri+要上传的文本名(包罗所在文件夹)+SAS
Token,然后把文件流HTTP PUT到那一个Url就能够完结上传。

上述代码生成的是一个仓储容器的SAS Url,其实也可以本着一个Blob对象生成SAS
Url。

别的索要专注的是,你也足以在储存容器上设定一个原则性的共享访问策略(而非临时设置在SAS
token上),那样你能够进一步方便和连串的支配SAS的有效性。详情可参看下面提到的文档。

安装跨域策略

直传文件实际上调用的是Azure Storage REST API,在初期的时候,Azure
Storage是不匡助跨域访问的(CORS),在那种场地下,唯有设置Storage容器的自定义域和Web应用程序的域一致。不过现在有了CORS的支撑,就很粗略了,通过上面的格局能够安装CORS(:

public static async Task AddCorsRuleAsync(CloudBlobClient blobClient)
{
    //First get the service properties from storage to ensure we're not adding the same CORS rule again.
    var serviceProperties =await blobClient.GetServicePropertiesAsync();
    var corsSettings = serviceProperties.Cors;
    var corsRule = corsSettings.CorsRules.FirstOrDefault(
        o => o.AllowedOrigins.Contains("http://localhost:3904"));//设置你自己的服务器地址
    if (corsRule == null)
    {
        //Add a new rule.
        corsRule = new CorsRule()
        {
            AllowedHeaders = new List<string> { "x-ms-*", "content-type", "accept" },
            AllowedMethods = CorsHttpMethods.Put,//Since we'll only be calling Put Blob, let's just allow PUT verb
            AllowedOrigins = new List<string> { "http://localhost:3904" },//This is the URL of our application.
            MaxAgeInSeconds = 1 * 60 * 60,//Let the browswer cache it for an hour
        };
        corsSettings.CorsRules.Add(corsRule);
        //Save the rule
        await blobClient.SetServicePropertiesAsync(serviceProperties);
    }
}

对于CORS越发详细的分解,可以参考Azure Storage的MSDN
Blog上的那篇文章《Windows Azure Storage: Introducing
CORS
》和Gaurav
Mantri的那篇博文《Windows Azure Storage and Cross-Origin Resource
Sharing (CORS) – Lets Have Some
Fun

集成WebUploader

在收获SAS并安装了CORS之后,最终的事体,就是哪些把公文提交到SAS
Url了。固然大家可以动用Ajax或HTML5原生的办法来发送文书(如上两篇小说中所演示的),不过利用一个共处的文件上传组件,应该是最便利(对用户也是如此)的章程了。

自家尝试了把Baidu
WebUploader集成,完结了多图片上传。在合龙的进程,一些小心的地点有:

  • 初始化uploader对象的时候,不要设置server属性,因为server地址须要动态获取(要获取SAS
    Url),且每个文件的SAS Url不平等(因为文件名不平等)
  • 本人是先事先获取SAS的token,然后在uploadStart事件中为每个文件生成元数据新闻,和分级的server地址
  • 在uploadBeforeSend事件中,来配置Azure所需的header信息
  • 在uploadSuccess事件中,把文件的元数据传递给后端服务器

切切实实的代码可以查看自己享受的代码片段:http://git.oschina.net/ike/codes/7edc84bio2zplhunyxvkr

最终,如果那篇文章对你有用,欢迎打赏。

相关文章