Set-AzApiManagementPolicy配置含函数的APIM策略报验证错误
Azure APIM操作级策略通过PowerShell部署报验证错误的解决方法
问题场景
- 尝试使用Azure Pipeline自动化构建API Management基础设施,目前已成功添加API及对应API操作,但在定义操作级别的专属策略时遇到部署报错问题。
- 编写了用于对接Service Bus队列的APIM策略(已简化复杂逻辑做演示),策略内容如下:
<policies> <inbound> <base /> <set-variable name="sasToken" value="@{ return "bob"; }" /> <set-header name="Authorization" exists-action="override"> <value>@(context.Variables.GetValueOrDefault<string>("sasToken"))</value> </set-header> <set-header name="Content-type" exists-action="override"> <value>application/json</value> </set-header> <set-header name="Ocp-Apim-Subscription-Key" exists-action="delete" /> <set-header name="BrokerProperties" exists-action="override"> <value>@{ return string.Format("{{\"SessionId\":\"{0}\"}}", "bob"); }</value> </set-header> <set-backend-service base-url="https://i365intfnapidevtbcoresb.servicebus.windows.net/i365intfnapidevtbcoresbqueue" /> </inbound> <backend> <base /> </backend> <outbound> <base /> </outbound> <on-error> <base /> </on-error> </policies>
- 上述策略可以在Azure API Management门户界面中正常录入保存,但将策略存为独立文件/内联变量,执行如下Azure PowerShell命令部署时触发报错:
Set-AzApiManagementPolicy -Context $apim_context -ApiId $apiId -OperationId addmessage -PolicyFilePath <path to policy xml file>
命令中
$开头的参数均为提前声明的自定义变量,执行后返回错误如下:Error Details: [Code= ValidationError, Message= 'bob' is an unexpected token. Expecting white space. Line 5, position 21., Target= representation]
- 核心问题:无法确定value属性/value元素内以
@{}开头的策略表达式的正确编写格式,通过Set-AzApiManagementPolicy命令部署时始终触发XML验证错误,需要该类策略用于命令行部署的正确格式规范。
错误根因
报错本质是XML转义规则冲突:在APIM门户中编辑策略时,后台会自动处理代码表达式里的特殊字符转义,但直接把门户里复制的策略内容存为XML文件执行PowerShell命令时,策略表达式里的双引号、尖括号等特殊字符没有做XML合规转义,导致XML解析器把C#表达式里的双引号识别成了XML属性的结束标记,最终抛出"意外token"的验证错误。
解决方法
对策略表达式里所有XML特殊字符做转义替换,转义规则如下:
- 双引号
"替换为" - 小于号
<替换为< - 大于号
>替换为> - 和号
&替换为& - 单引号
'替换为'
以上述示例策略为例,转义后可正常通过PowerShell部署的合法XML策略内容如下:
<policies> <inbound> <base /> <set-variable name="sasToken" value="@{ return "bob"; }" /> <set-header name="Authorization" exists-action="override"> <value>@(context.Variables.GetValueOrDefault<string>("sasToken"))</value> </set-header> <set-header name="Content-type" exists-action="override"> <value>application/json</value> </set-header> <set-header name="Ocp-Apim-Subscription-Key" exists-action="delete" /> <set-header name="BrokerProperties" exists-action="override"> <value>@{ return string.Format("{{\"SessionId\":\"{0}\"}}", "bob"); }</value> </set-header> <set-backend-service base-url="https://i365intfnapidevtbcoresb.servicebus.windows.net/i365intfnapidevtbcoresbqueue" /> </inbound> <backend> <base /> </backend> <outbound> <base /> </outbound> <on-error> <base /> </on-error> </policies>
避坑提示
- 如果使用内联策略传参(不读取本地文件),除了XML转义外,还要注意PowerShell本身的字符串转义规则,建议用单引号包裹整段策略XML,避免PowerShell提前解析
$开头的变量名。 - 不要额外做HTML实体编码的反向处理,严格遵循XML转义规则即可通过命令行部署校验。
内容的提问来源于stack exchange,提问作者TimBunting
相关产品推荐
相关产品推荐

