如何在 Azure Functions (v2) 上启用 GZIP 压缩?
我与邮递员检查过,它没有显示 GZIP
POST /api/values HTTP/1.1
Host: HOSTNAMEHERE.azurewebsites.net
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: e2c3967b-f562-df35-a3d1-01bd56cb4b76
这是我的错误。
当达到该功能时,GZip 似乎默认配置为 ON :)
就我而言,我使用的是本地功能,它没有附带 Gzip:
Content-Type →application/json; charset=utf-8
Date →Mon, 19 Mar 2018 00:55:06 GMT
Server →Kestrel
Transfer-Encoding →chunked
我注意到,当我在 Azure 上调用正确的 URL 时,就会出现:
Content-Encoding →gzip
Content-Type →application/json; charset=utf-8
Date →Sat, 17 Mar 2018 17:29:46 GMT
Server →Kestrel
Transfer-Encoding →chunked
Vary →Accept-Encoding
X-Powered-By →ASP.NET
对于任何寻求相同答案但使用 AzFunc Linux 部署 的人来说,上述自动处理似乎仍未得到完全支持。
更多信息。 Github 问题仍然开放:https://github.com/Azure/azure-functions-host/issues/7285
但是,可以在代码中手动启用它,假设您可以调整代码以在启用压缩后直接写入响应正文...
我在这里提供了一个带有实现的要点:https://gist.github.com/cajuncoding/a4a7b590986fd848b5040da83979796c
这样就可以实现如下:
[FunctionName(nameof(MyHttpTriggerWithResponseCompressionSuppport))]
public Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "compressed-response-api")] HttpRequest req, ILogger logger)
{
req.EnableResponseCompression();
var httpResponse = req.HttpContext.Response;
httpResponse.Headers.ContentType = "application/json";
//DO some work and write to the HttpContext Response Body stream... all content will be compressed...
await using var responseWriter = new StreamWriter(httpResponse.Body, Encoding.UTF8, leaveOpen: true);
await responseWriter.WriteAsync(JsonSerializer.Serialize<object>(new
{
Topic = "Hello World...I'm Compressed!",
Body = "If I was some big JSON then I'd be nicely packed for transmission!"
}, new JsonSerializerOptions() {WriteIndented = true}));
return new EmptyResult();
}
以下是供后代使用的要点的来源:
using System.IO.Compression;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
namespace AzureFunctionsInProcessCompressionExtensions
{
/// <summary>
/// BBernard / CajunCoding (MIT License)
/// Original Gist: https://gist.github.com/cajuncoding/a4a7b590986fd848b5040da83979796c
/// Extension method for the HttpContext & HttpRequest to enable response compression within Azure Functions using the In Process Model -- which
/// does not support custom Middleware so it cannot easily intercept & handle all requests.
/// There are many issues reported with response compression not always working, particularly with Linux deployments,
/// therefore this helps to easily enable this for any request by simply calling the extension method in the Function invocation.
/// It works by simply inspecting the AcceptEncoding header to determine which, if any, compression encodings are supported (Gzip, Brotli, Deflate)
/// and then wrapping the Response Body Stream with the correct implementation to encode the response while also setting the correct Response Header
/// for the Client to correctly decode the response.
///
/// This works great with GraphQL via Azure Functions (In Process Model) using HotChocolate GraphQL server allowing for compression of large
/// GraphQL Query results which can significantly improve performance in use cases with large query result sets.
/// </summary>
internal static class AzureFunctionsInProcessCompressionExtensions
{
public static class AcceptCompressionNames
{
public const string Gzip = "gzip";
public const string Brotli = "br";
public const string Deflate = "deflate";
}
public static HttpRequest EnableResponseCompression(this HttpRequest httpRequest)
=> httpRequest.HttpContext.EnableResponseCompression().Request;
public static HttpContext EnableResponseCompression(this HttpContext httpContext, CompressionLevel compressionLevel = CompressionLevel.Fastest)
{
var acceptCompressionTypes = httpContext.Request.Headers.AcceptEncoding
.SelectMany(v => v.Split(','))
.Select(v => v.Trim().ToLower())
.ToArray();
if (acceptCompressionTypes.Length <= 0)
return httpContext;
var httpResponse = httpContext.Response;
var responseStream = httpResponse.Body;
var responseHeaders = httpResponse.Headers;
foreach (var compressionType in acceptCompressionTypes)
{
switch (compressionType)
{
case AcceptCompressionNames.Gzip:
httpResponse.Body = new GZipStream(responseStream, compressionLevel, leaveOpen: false);
responseHeaders.ContentEncoding = new StringValues(AcceptCompressionNames.Gzip);
return httpContext;
case AcceptCompressionNames.Brotli:
httpResponse.Body = new BrotliStream(responseStream, compressionLevel, leaveOpen: false);
responseHeaders.ContentEncoding = new StringValues(AcceptCompressionNames.Brotli);
return httpContext;
case AcceptCompressionNames.Deflate:
httpResponse.Body = new DeflateStream(responseStream, compressionLevel, leaveOpen: false);
responseHeaders.ContentEncoding = new StringValues(AcceptCompressionNames.Deflate);
return httpContext;
}
}
return httpContext;
}
}
}