如何通过 Azure 函数上传大文件?

How to upload a large file through an Azure function?

我正在探索 Azure Functions。到目前为止,我测试过的场景效果很好。

我正试图找出一种通过 Azure 函数上传文件 (20MB+) 的方法。

想法是 Azure Functions 在保留请求的流并将其保存到 BLOB 存储之前首先验证是否允许经过身份验证的用户上传文件。

这是客户端的代码,它创建一个 StreamContent 以将字节传送到服务器:

using (Stream fileStream = ...)
{
    var streamContent = new StreamContent(fileStream);

    streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
    streamContent.Headers.ContentLength = fileStream.Length;
    streamContent.Headers.Add("FileId", fileId);

    var responseMessage = await m_httpClient.PutAsync(<validURI>, streamContent);

    responseMessage.EnsureSuccessStatusCode();

    succeeded = true;
}

这是服务器端的代码。

[FunctionName("upload-data")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "put")]HttpRequestMessage req, TraceWriter log)
{
    try
    {
         //  Initialize stuff.

         //  Validate authenticated user & privileges.  

         //  Get the content stream of the request and 
         //  save it in the BLOB storage.

         return req.CreateResponse(HttpStatusCode.OK);
    }
    catch (Exception exc)
    {
        return req.CreateResponse(HttpStatusCode.InternalServerError, exc);
    }
}

我在方法的开头放置了一个断点。我期望在客户端发送请求后立即命中断点,无论文件有多大。然而事实并非如此。

我猜测 Azure 函数在调用方法之前以某种方式尝试获取请求正文的所有内容。我还认为我发送的文件可能超过基础 Web 作业的 4 MB 限制,但我没有找到配置该文件的方法。

是否可以通过流式传输将大文件上传到 Azure Functions? 有没有办法让这个工作?

设置 ContentLength header 后,您将不再流式传输它。您需要使用 PushStreamContent class 并以块的形式写入流。

我不知道您是否仍然能够在服务器端以块的形式访问该流。 Azure Functions 管道中的某些内容可能会在将流提供给函数之前对其进行缓冲。

Kzrystof,你在这里遵循了一个错误的做法。 Azure Functions 不适用于与客户端设备的长期通信。我不确定,为什么有人可能有兴趣指导您编写一个程序来管理 Azure Function 并强制它做它不打算做的事情。

Large, long-running functions can cause unexpected timeout issues.

现在想象一下,您可能拥有良好的 Internet 连接,但用户可能不是。在进行任何操作之前,您还必须注意其他几个问题。这是官方文档的摘录,https://docs.microsoft.com/en-us/azure/azure-functions/functions-best-practices

如果我必须设计这个应用程序,我会使用 App Service → Azure Storage → Azure Functions。这将是我的应用程序架构的工作流程。

在设计上,我的应用程序会轮流处理这些信息,比如App Service可以负责图片上传,我可以指定用户是否可以上传。 ASP.NET Core 或任何其他语言或框架可用于开发 Web 应用程序的这一端,而且您知道这可以轻松提升以支持最大 20MB 的文件上传。

为什么我要你扭曲设计?你有一个 Blob 函数,我建议一个 Blob 函数,因为,

Functions should be stateless and idempotent if possible. Associate any required state information with your data. For example, an order being processed would likely have an associated state member. A function could process an order based on that state while the function itself remains stateless.

函数本身是无状态的,这意味着它们不能保存关于任何东西的任何信息,解决这个问题需要你有另一个中间件(或 frontware)来与之通信身份服务器,这就是为什么我建议在这里使用应用程序服务,因为它可以包含对用户进行身份验证的必要信息,然后是 Blob 和 &rarr 最后是函数,如果需要.

然后,一旦它离开那里,进入 Azure 存储,我就可以让 WebHooks,或者直接的 Blob 存储触发器从那里负责委托并在 Azure 函数中处理图像——如果有的话不再需要该功能。查看如何使用 Blob 存储触发器来启动用于各种目的的函数,https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-storage-blob-triggered-function

我找到了另一种做事的方法。这是适合我的解决方案。

当客户端需要上传文件时,它调用 Azure Function 进行身份验证(使用框架提供的身份)和授权(它可以是 Table 存储中的简单目标检查,意思是(她)他允许做这样的操作)。

Azure 函数将请求共享访问签名来访问特定的 Blob。 SAS 将允许客户端在有限的时间内以只写权限访问 Blob 存储(注意 Azure 上的时钟偏差)。

然后客户端将使用返回的 SAS 将文件直接上传到 Blob 存储。这样一来,它避免了 Afzaal Ahmad Zeeshan 提到的与客户端的长期通信,并进一步降低了总体成本,因为 Azure Function 不再依赖于客户端的连接速度。

另一种解决方案(可能不是最佳做法)是使用块发布文件。但这需要您跟踪这些块并在之后整合它们。

例如:

  • 前端 - 将多个块发送到端点(多个 POST)
  • 后端 - 存储块
  • 前端 - 发送完成后,与端点确认
  • 后端 - 合并块

Dropzone JS - Chunking