Я хочу оценить лайм на основе атрибута mailTo из тела запроса.
Вот политика APIM
<rate-limit-by-key calls = "5"
renewal-period = "10"
counter-key = "@(context.Request.Body.As<JObject>()["mailTo"].ToString())" />
Вот тело запроса
{
"mailTo": "[email protected]"
}
Это отлично работает для прямого вызова бэкэнда, но при вызове APIM возникает ошибка ниже.
{
"errors": {
"": [
"A non-empty request body is required."
]
},
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-......-3be881755d918044-00"
}`
<rate-limit-by-key calls = "5"
renewal-period = "10"
counter-key = "@(context.Request.Body.As<JObject>()["mailTo"].ToString())" />


Я использовал ту же политику в формате ниже, и она работала, как ожидалось.
Policy
<policies>
<inbound>
<base />
<rate-limit-by-key calls = "5" renewal-period = "10" counter-key = "@(context.Request.Body.As<JObject>()["mailTo"].ToString())" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
Test Result


Trace

Думаю, в политике гораздо больше логики.
Эта простая политика не вызывает упомянутой ошибки:
<policies>
<inbound>
<base />
<rate-limit-by-key calls = "5" renewal-period = "10" counter-key = "@(context.Request.Body.As<JObject>()["mailTo"].ToString())" />
<return-response>
<set-status code = "200" reason = "Ok" />
<set-body>{
"message": "It's fine!"
}</set-body>
</return-response>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
Но я предполагаю, что тело запроса используется в политике как минимум дважды.
Поэтому вы должны установить параметр preserveContent на true:
context.Request.Body.As<JObject>(true)["mailTo"].ToString()
https://learn.microsoft.com/en-us/azure/api-management/api-management-policy-expressions
Чтобы избежать этого и заставить метод работать с копией основного потока, установите для параметра saveContent значение true.
Политика, которая использует запрос дважды:
<policies>
<inbound>
<base />
<rate-limit-by-key calls = "5" renewal-period = "10" counter-key = "@(context.Request.Body.As<JObject>(true)["mailTo"].ToString())" />
<set-variable name = "email" value = "@(context.Request.Body.As<JObject>(true)["mailTo"]?.ToString().ToLower())" />
<return-response>
<set-body template = "none">@{
var jsonResponse = new JObject();
jsonResponse.Add(new JProperty("message", (string)context.Variables["email"]));
return jsonResponse.ToString();
}</set-body>
</return-response>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
Эта политика сработала! параметр от
preserveContentдоtrue:<rate-limit-by-key calls = "2" renewal-period = "60" counter-key = "@(context.Request.Body.As<JObject>(true)["email"].ToString())" />