Azure API Management中return-response调用POST API返回400错误排查
解决Azure API Management出站策略POST调用400错误问题
问题场景
我在Azure API Management的出站策略中设置逻辑:检查GET API的响应体,若entityStatus字段值为0,则返回提示消息;若值为1,则调用外部POST API并返回其响应。
原策略代码:
<set-variable name="id" value="" /> <set-variable name="newRequest" value="@(context.Request.Body?.As<JObject> (preserveContent: true))" /> <choose> <when condition="@(context.Response.StatusCode == 200 && (int)context.Response.Body?.As<JObject>(true)["entityStatus"] == 1)"> <send-request mode="new" timeout="20" response-variable-name="id" ignore-error="false"> <set-url>@($"https://api.dev/external/workrequest/wr")</set-url> <set-method>POST</set-method> <set-header name="Content-Type" exists-action="override"> <value>application/json</value> </set-header> <set-header name="Authorization" exists-action="override"> <value>@(context.Request.Headers.GetValueOrDefault("Authorization","scheme param"))</value> </set-header> <set-body>@{ var document = (JObject)context.Variables["newRequest"]; return document?.ToString(); }</set-body> </send-request> <return-response response-variable-name="id"> <set-status code="200" reason="OK" /> <set-header name="Content-Type" exists-action="override"> <value>application/json</value> </set-header> <set-body>@((((IResponse)context.Variables["id"]).Body.As<JObject>()).ToString())</set-body> </return-response> </when> <when condition="@(context.Response.StatusCode == 200 && (int)context.Response.Body?.As<JObject>(true)["entityStatus"] == 0)"> <return-response> <set-status code="500" reason="VOID" /> <set-header name="Content-Type" exists-action="override"> <value>application/json</value></set-header> <set-body>The record is void</set-body> </return-response> </when> <otherwise /> </choose>
错误现象
当entityStatus为0时返回正常,但为1时触发400错误:
{ "type": "https://httpstatuses.io/400", "title": "Bad Request", "status": 400, "traceId": "00-317b53ba7a76f19b6153ca6ab14c5190-e9c27cf9162e2414-00" }
解决方案
1. 修正请求体来源(核心问题)
原策略中newRequest变量取的是原GET请求的Body,但GET请求通常没有Body,导致传递给外部POST API的内容为空,触发400错误。需要改为从GET API的响应体中提取数据作为POST请求体:
<!-- 替换原newRequest变量,从响应体获取数据 --> <set-variable name="responseBody" value="@(context.Response.Body?.As<JObject>(preserveContent: true))" /> <!-- 在send-request的set-body中使用响应体数据 --> <set-body>@{ var document = (JObject)context.Variables["responseBody"]; // 若外部API需要特定字段,可在此筛选,如return document["targetField"]?.ToString(); return document?.ToString(); }</set-body>
2. 添加日志排查请求内容
在send-request前添加日志,确认传递给外部API的内容是否符合要求:
<trace source="POST-Request-Debug" severity="information">@($"POST Body: {((JObject)context.Variables["responseBody"]).ToString()}")</trace>
3. 优化返回响应逻辑
添加空值判断,避免强制转换异常,并保留外部API的原始状态码:
<return-response response-variable-name="externalResponse"> <set-status code="@(((IResponse)context.Variables["externalResponse"]).StatusCode)" reason="@(((IResponse)context.Variables["externalResponse"]).ReasonPhrase)" /> <set-header name="Content-Type" exists-action="override"> <value>application/json</value> </set-header> <set-body>@{ var externalResponse = (IResponse)context.Variables["externalResponse"]; return externalResponse.Body?.As<JObject>(preserveContent: true)?.ToString() ?? "{}"; }</set-body> </return-response>
完整修复后策略示例
<set-variable name="responseBody" value="@(context.Response.Body?.As<JObject>(preserveContent: true))" /> <choose> <when condition="@(context.Response.StatusCode == 200 && (int)context.Response.Body?.As<JObject>(true)["entityStatus"] == 1)"> <trace source="EntityStatus-1" severity="information">@("触发外部POST API调用")</trace> <send-request mode="new" timeout="20" response-variable-name="externalResponse" ignore-error="false"> <set-url>@($"https://api.dev/external/workrequest/wr")</set-url> <set-method>POST</set-method> <set-header name="Content-Type" exists-action="override"> <value>application/json</value> </set-header> <set-header name="Authorization" exists-action="override"> <value>@(context.Request.Headers.GetValueOrDefault("Authorization","scheme param"))</value> </set-header> <set-body>@{ var document = (JObject)context.Variables["responseBody"]; return document?.ToString(); }</set-body> </send-request> <return-response response-variable-name="externalResponse"> <set-status code="@(((IResponse)context.Variables["externalResponse"]).StatusCode)" reason="@(((IResponse)context.Variables["externalResponse"]).ReasonPhrase)" /> <set-header name="Content-Type" exists-action="override"> <value>application/json</value> </set-header> <set-body>@{ var externalResponse = (IResponse)context.Variables["externalResponse"]; return externalResponse.Body?.As<JObject>(preserveContent: true)?.ToString() ?? "{}"; }</set-body> </return-response> </when> <when condition="@(context.Response.StatusCode == 200 && (int)context.Response.Body?.As<JObject>(true)["entityStatus"] == 0)"> <return-response> <set-status code="500" reason="VOID" /> <set-header name="Content-Type" exists-action="override"> <value>application/json</value></set-header> <set-body>The record is void</set-body> </return-response> </when> <otherwise /> </choose>
内容的提问来源于stack exchange,提问作者Shree
相关产品推荐
相关产品推荐

