如何延迟读取触发 HTTP 请求的正文,直到稍后在 Azure 函数中?
Posted
技术标签:
【中文标题】如何延迟读取触发 HTTP 请求的正文,直到稍后在 Azure 函数中?【英文标题】:How to delay reading the body of the trigger HTTP request until later in an Azure Function? 【发布时间】:2020-04-12 05:22:08 【问题描述】:我正在使用 Azure Functions 处理以 base64 编码并在 Json 中传递的大型 (>20MB) 文件。
在读取和解析 JSON 正文之前,我需要通过 HTTP 请求标头中传递的 API 密钥对客户端进行身份验证。
分析日志,似乎在执行函数之前就读取了整个 JSON。
有没有办法可以延迟读取 JSON 正文,直到我对用户进行身份验证?
编辑:
函数声明如下:
public static class V1Functions
[FunctionName("V1MyFunction")]
public static async Task<IActionResult> MyFunction(
[HttpTriggerAttribute(AuthorizationLevel.Anonymous, "post", Route = "v1/my_function")] HttpRequest request,
ILogger logger)
//...
【问题讨论】:
我知道 JSON 中 20MB 的 base64 编码文件远非一个好习惯,但 ::shrug:: 这些是要求。 你能以任何方式修改客户端吗?例如,在带有有效负载的 POST 之前向您发送带有 API 密钥的 HEAD 请求。然后,您可以返回他们需要包含在 POST 中的质询标头。 实际上,既然你在问,你可能不能:)。在将请求正文读入请求对象(然后将其传递到您的代码中)后,您的功能代码将触发。我会说放弃它并切换到像 ASP.NET Core 这样的原始东西。 @evilSnobu 你知道函数过滤器(例如 OnExecutingAsync)是否有帮助吗? 我不知道他们的存在。看起来很有希望。我会在这里提出一个问题并询问 Azure Functions 的开发人员 - github.com/Azure/azure-functions-host 【参考方案1】:我遇到了类似的问题,传入的请求必须在执行之前进行身份验证。然而,我并不真正关心内容的大小(它不应该达到例如~20MB)。因此,我不确定这种方法是否真的符合您的需求。
正如您在评论中所述,OnExecutingAsync
可用于将要执行的代码放置在函数本身之前。问题是,OnExecutingAsync
只是一个任务;你不能真正从中返回任何东西 - 如果可以这样做会很好,因为它可以让我们返回例如“Unauhorized”,通常在谈论 http 请求时就是这种情况。
在任何情况下,无论它是否符合您的要求,这里是:在我看来,请求将内容作为流保存,并且 afaik 它还没有被 http 触发管道处理,至少直到你打电话给例如ReadAsStringAsync
或类似的东西。
使用实现IFunctionInvocationFilter
的 BaseController,类似于:
注意:截至 2019 年 12 月 29 日,IFunctionInvocationFilter
仍处于预览阶段。
internal abstract class BaseController : IFunctionInvocationFilter
protected bool _IsAuthenticated = false;
private IAuthenticationService _AuthenticationService;
protected BaseController(IAuthenticationService authenticationService)
_AuthenticationService = authenticationService;
public virtual async Task OnExecutedAsync(FunctionExecutedContext executedContext, CancellationToken cancellationToken)
_IsAuthenticated = false;
public virtual async Task OnExecutingAsync(FunctionExecutingContext executingContext, CancellationToken cancellationToken)
// This part is a tad flimsy, but I never managed to find a better way of retrieving the header values
// You could probably investigate the FunctionExecutingContext a tad more and see if you can come up with something better
if (executingContext.Arguments.TryGetValue("request", out var request) && request is HttpRequest httpRequest)
_IsAuthenticated = _AuthenticationService.Authenticate(httpRequest.Headers);
else
_IsAuthenticated = false;
protected async Task<IActionResult> DoAuthenticated(Func<Task<IActionResult>> action)
return !IsAuthenticated ? Unauthenticated() : await action();
protected virtual IActionResult Unauthenticated()
var someErrorHandlingWithSomeModelAsBody = ...
return new UnauthorizedObjectResult(someErrorHandlingWithSomeModelAsBody);
AuthenticationService能够判断头部中的key是否有效。
您可能已经注意到依赖注入的使用(这正是我制作的函数应用程序的实现方式),您可能可以轻松地纠正这一点,根据需要使事物变为静态。
示例控制器类似于:
public class SampleController : BaseController
private readonly ISampleService _SampleService;
public SampleController(ISampleService sampleService, IAuthenticationService authenticationService) : base(authenticationService)
_SampleService = sampleService;
[FunctionName(nameof(SampleFunction))]
public async Task<IActionResult> SampleFunction(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "v1/my_function")] HttpRequest request,
ILogger log)
try
return await DoAuthenticated(async () =>
var largeFileAsString = await request.Content.ReadAsStringAsync();
return await _SampleService.HandleLargeFile(largeFileAsString);
catch (Exception e)
// If you need exception handling...
每当SampleFunction
被触发时,都会按以下顺序执行:
OnExecutingAsync
-body
SampleFunction
-body - 只有在 OnExecutingAsync
期间验证实际上成功时才会执行该 func
OnExecutedAsync
-body
问题是,即使身份验证失败,该函数是否仍能处理您所说的整个 20MB 的 JSON 内容。如果您对此进行测试,我个人实际上会对结果感兴趣。
【讨论】:
【参考方案2】:您可以使用 Azure 应用服务内置的身份验证和授权支持(easy auth)对用户进行身份验证。有关 Azure 应用服务轻松身份验证的详细信息,请参阅 here。
Azure 函数基于 Azure 应用服务,因此也为 Azure 函数启用。
This section 表示它是如何工作的:
每个传入的 HTTP 请求在被处理之前都会经过它 您的应用程序代码。
我认为这是您正在寻找的身份验证方式:在用户通过身份验证之前不处理代码中的请求数据。 This blog将有助于您使用Azure功能和Easy Auth。
希望对你有帮助。
【讨论】:
他不能。您错过了他从标头中读取 API 密钥的部分。以上是关于如何延迟读取触发 HTTP 请求的正文,直到稍后在 Azure 函数中?的主要内容,如果未能解决你的问题,请参考以下文章
Azure Function App HTTP 触发来自请求正文的 CosmosDB 输入查询
如何使用 HTTP 请求触发 Firebase 函数以从多个节点读取数据?