问题描述

使用APIM,在 Inbound 中对请求的Body内容进行解析。客户端请求所传递的Request Body为XML格式,需要从Request Body中解析出多个(Element)节点值,然后设置通过(set-variable)为参数在后续使用。

但是验证发现,当且只当使用一个set-variable 从 Request Body中读取数据时候,是可以成功的。如果要读取第二个,第三个时,始终会遇见一个诡异的错误 Expression evaluation failed. Object reference not set to an instance of an object。 关键问题是,为什么第一个可以成功,第二个的语句和第一个完全一样,却面临如此问题?真是诡异!

 

需要解析的XML格式如下:

202203081007001

Cheng Du Junyi Hotel

ICP1009100

在APIM Policies中,需要获取 ID, Name, Code 和 Desc 值,策略语句如下:

)" />

)" />

)" />

)" />

@((string)context.Variables["myID"])

@((string)context.Variables["myName"])

@((string)context.Variables["myCode"])

@((string)context.Variables["myDesc"])

在APIM的Test功能,查看Trace语句后,错误消息为:

set-variable (0.905 ms)

{

"message": "Expression was successfully evaluated.",

"expression": "\n context.Request.Body.As().Descendants().FirstOrDefault(x => x.Name.LocalName == \"ID\")?.Value\n ",

"value": "202203081007001"

}

set-variable (0.013 ms)

{

"message": "Context variable was successfully set.",

"name": "myID",

"value": "202203081007001"

}

set-variable (7.898 ms)

{

"messages": [

{

"message": "Expression evaluation failed.",

"expression": "\n context.Request.Body.As().Descendants().FirstOrDefault(x => x.Name.LocalName == \"Name\")?.Value\n ",

"details": "Object reference not set to an instance of an object."

},

"Expression evaluation failed. Object reference not set to an instance of an object.",

"Object reference not set to an instance of an object."

]

}

说明:

绿色高亮部分为Set-Variable的语句,两者语法完全一样。

但第二次就出现了 未将对象应用到实例的异常。

错误截图:

 

 

问题解决

经过反复实验,问题肯定出现在 context.Request.Body.As 上,是不是这个内容只能使用一次呢? 经 Google 搜寻,终于得出了官方解释和解决办法:

官方解释

文档链接:https://docs.microsoft.com/en-us/azure/api-management/api-management-policy-expressions#ContextVariables

context.Request.Body.As 和 context.Response.Body.As 方法用As的方式指定读取 Request 和 Response的Body内容,默认情况下,这个方式读取的时原始消息的Body流,读取一次后就变为不可用,也就是说只能 As的方式一次。这就解释了为什么第二个Set Variable语句出现 Object 异常。

解决办法

正如文档中解释,使用 preserveContent : true 后,可以多次转换  Body Stream。

修改后的Policy为:

)" />

)" />

)" />

)" />

修改后,测试解析XML文件动画:

 

注意:

因为APIM实例的内存存在限制,内部的Memory限制为500MB,当缓存的Request/Response的内容大于500MB的时候,就会出现 MessagePayLoadTooLarge异常。

当使用 preserveContent:true 后,会把当前的Body内容缓存在APIM实例的内存中,如果Body内容大于500MB,则会出现 MessagePayLoadTooLarge问题,所以对于Body Size过大的请求,不能使用 Buffer 及读取整个Response/Request Body在Policy代码中。

 

参考资料

API Management policy expressions - Context variable - IMessageBody : https://docs.microsoft.com/en-us/azure/api-management/api-management-policy-expressions#ContextVariables

Get an attribute value from XML Response in azure apim : https://stackoverflow.com/questions/68618339/get-an-attribute-value-from-xml-response-in-azure-apim

XElement Class : https://docs.microsoft.com/en-us/dotnet/api/system.xml.linq.xelement?view=net-6.0

 

文章来源

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。