`PostAsJsonAsync` 在Azure Functions中返回500内部服务器错误,而Postman以及使用 `StringContent` 的 `PostAsync` 可以成功
我在一个ASP.NET Core 8.0应用中,使用 IHttpClientFactory 调用Azure Functions的 HTTP触发器(v4、Node.js、消费计划)。该函数具有 authLevel: 'function',密钥作为查询参数传递。
使用 PostAsJsonAsync 一直返回500,并且响应体为空:
var client = _httpClientFactory.CreateClient("MyClient");
var payload = new object();
var response = await client.PostAsJsonAsync("api/myfunction", payload, ct);
// response.StatusCode == 500, response.Content has Content-Length: 0
从Postman或 PowerShell的 Invoke-WebRequest 发出的同一请求返回200 OK。
我尝试了以下方法:
- HTTP版本:Postman也使用HTTP/2,但仍然工作
Content-Type:尝试application/json和application/json; charset=utf-8,两者都返回500- 载荷:甚至
new object()(序列化为{})也返回500 - 身份验证:密钥是正确的;错误的密钥返回401,而不是500
- 函数代码:日志显示根本没有调用,因此500在处理程序运行之前就已经返回
切换到 PostAsync 与 StringContent 可以解决:
var client = _httpClientFactory.CreateClient("MyClient");
var payload = new object();
var json = JsonSerializer.Serialize(payload);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync("api/myfunction", content, ct);
// response.StatusCode == 200
据我所见似乎无关,但为了完整性,这里给出Azure函数的实现:
app.http('postSnapshot', {
methods: ['POST'],
authLevel: 'function',
route: 'snapshot',
handler: async (request, context) => {
let body;
try {
const text = await request.text();
context.log('postSnapshot body (%d bytes): %s', text.length, text.slice(0, 500));
body = JSON.parse(text);
} catch (err) {
context.log.error('postSnapshot parse error:', err.message);
return { status: 400, body: `Invalid JSON body: ${err.message}` };
}
如前所述,日志和响应体为空。
PostAsJsonAsync 有什么不同,导致Azure Functions在基础设施层面拒绝请求?确实想理解 为什么 修复能起作用。我真的不喜欢那种“工作,但不知道为什么”的情况。更希望“工作,而且知道原因”。 :-)
解决方案
PostAsJsonAsync 实际上是一个扩展方法,它使用 JsonContent 而不是 StringContent。问题可能是 JsonContent 默认使用分块编码(chunked encoding),这在Azure Logic Apps的 HTTP触发器中被记录为一个问题。更多信息请参见 这个Github问题:
I have to say the Azure Logic App HTTP trigger doesn't support "chunked encoding". In Handle large messages with chunking in Azure Logic Apps doc, it says:
Logic App triggers don't support chunking because of the increased overhead of exchanging multiple messages.
I was trying to POST a message to Azure Logic App with a HTTP trigger. It because HttpClient's
PostAsJsonAsyncONLY support chunked encoding. I know what @davidfowl said not recommend buffering for large JSON payloads, but most of the payload to the Azure Logic App are really small. I think it should have an straightforward option to usePostAsJsonAsyncwithout chunked encoding.
你可以测试文中提到的 变通方法,以验证这是不是Azure Functions HTTP触发器的问题。
var content = JsonContent.Create<T>(json);
await content.LoadIntoBufferAsync();
var response = await httpClient.PostAsync(url, content);
如果有帮助,你可以把代码很容易地改造成一个与 PostAsJsonAsync 类似的方便扩展方法。