如何从 HTTP 触发的 Azure 函数返回 blob?
Posted
技术标签:
【中文标题】如何从 HTTP 触发的 Azure 函数返回 blob?【英文标题】:How do I return a blob from a HTTP triggered Azure Function? 【发布时间】:2019-08-25 05:44:13 【问题描述】:我正在尝试使用 Azure 函数从 Blob 存储返回文件。就目前而言,我已经让它工作了,但是通过将整个 blob 读入内存,然后将其写回,它的工作效率很低。这适用于小文件,但是一旦它们变得足够大,效率就会非常低。
如何让我的函数直接返回 blob 而不必将其完全读入内存?
这是我目前正在使用的:
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, Binder binder, TraceWriter log)
// parse query parameter
string fileName = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
.Value;
string binaryName = $"builds/fileName";
log.Info($"Fetching binaryName");
var attributes = new Attribute[]
new BlobAttribute(binaryName, FileAccess.Read),
new StorageAccountAttribute("vendorbuilds")
;
using (var blobStream = await binder.BindAsync<Stream>(attributes))
if (blobStream == null)
return req.CreateResponse(HttpStatusCode.NotFound);
using(var memoryStream = new MemoryStream())
blobStream.CopyTo(memoryStream);
var response = req.CreateResponse(HttpStatusCode.OK);
response.Content = new ByteArrayContent(memoryStream.ToArray());
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") FileName = fileName ;
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return response;
我的function.json
文件:
"bindings": [
"authLevel": "anonymous",
"name": "req",
"type": "httpTrigger",
"direction": "in",
"methods": [
"get",
"post"
]
,
"name": "$return",
"type": "http",
"direction": "out"
],
"disabled": false
我既不是 C# 开发人员,也不是 Azure 开发人员,所以大部分内容我都忽略了。
【问题讨论】:
您不能只返回文件的链接以及共享访问签名吗? @CSharpRocks 老实说,我什至不知道这是一件事......这可能就是我需要的。如果您将其写为答案,我很乐意接受。谢谢! 【参考方案1】:我确实喜欢下面的最小内存占用(没有将完整的 blob 保存到内存中的字节中)。请注意,我不是绑定到流,而是绑定到 ICloudBlob
实例(幸运的是,C# 函数支持多种风格的 blob input binding)并返回打开的流。使用内存分析器对其进行了测试,即使对于大型 blob 也没有内存泄漏。
注意:您不需要寻求流位置 0 或刷新或处置(处置将在响应结束时自动完成);
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Azure.Storage.Blob;
namespace TestFunction1
public static class MyFunction
[FunctionName("MyFunction")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "video/fileName")] HttpRequest req,
[Blob("test/fileName", FileAccess.Read, Connection = "BlobConnection")] ICloudBlob blob,
ILogger log)
var blobStream = await blob.OpenReadAsync().ConfigureAwait(false);
return new FileStreamResult(blobStream, "application/octet-stream");
【讨论】:
为什么要使用ConfigureAwait(false),不使用会不会出问题? @adR , devblogs.microsoft.com/dotnet/configureawait-faq【参考方案2】:我喜欢 @CSharpRocks 关于创建 SAS 并将链接返回到 blob 存储的建议,但我也发现这篇文章可能相关:
https://anthonychu.ca/post/azure-functions-static-file-server/
以下是相关代码:
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(memoryStream);
response.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/octet-stream");
return response;
【讨论】:
我很确定这是我最初尝试的,但发现它不起作用:github.com/Azure/azure-functions-host/issues/1666【参考方案3】:感谢@krishg 的回答!
根据您的代码,我想出了相反的方法,将二进制数据从我的 Unity 发布到尽可能干净的 blob 文件。
[FunctionName("Upload")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "options", "put", Route = "upload/name")] HttpRequest req,
[Blob("container/name.bin", FileAccess.Write)] ICloudBlob blob, ILogger log)
if (req.Method == "OPTIONS")
req.HttpContext.Response.Headers.Add("access-control-allow-methods", "PUT, OPTIONS");
req.HttpContext.Response.Headers.Add("access-control-allow-headers", "Content-Type");
return new EmptyResult();
await blob.UploadFromStreamAsync(req.Body).ConfigureAwait(false);
return new OkObjectResult("data saved");
【讨论】:
以上是关于如何从 HTTP 触发的 Azure 函数返回 blob?的主要内容,如果未能解决你的问题,请参考以下文章
从 Azure Python HTTP 触发函数调用 Azure 逻辑应用
将参数从逻辑应用电子邮件触发器传递到 azure 函数 http 触发器问题
如何从 Azure 函数内部发出基于承诺的 HTTP 发布请求 (NodeJS)?