使用Bicep部署XML策略到Azure APIM时遇语法错误求助
Azure APIM策略部署错误修复
错误提示
'=' 是意外令牌。预期令牌为 ';'。第13行,位置58。
原XML策略代码
<policies> <inbound> <base /> <choose> <when condition="@(!context.Variables.ContainsKey('cachedAccessToken') || DateTime.UtcNow >= (DateTime)context.Variables['tokenExpiry'])"> <set-backend-service id="apim-generated-policy" backend-id="{0}" /> <send-request mode="new" response-variable-name="tokenResponse" timeout="20" ignore-error="false"> <set-url>{1}/token</set-url> <set-method>POST</set-method> <set-header name="Content-Type" exists-action="override"> <value>application/x-www-form-urlencoded</value> </set-header> <set-body>@("grant_type=password&username={2}&password=thisShouldRefThe-AmxPassword-NamedValue")</set-body> </send-request> <set-variable name="tokenResponseJson" value="@{{ return JsonConvert.DeserializeObject((string)context.Variables['tokenResponse'].Body.As<string>()); }}" /> <set-variable name="cachedAccessToken" value="@{{(string)context.Variables['tokenResponseJson']['access_token']}}" /> <set-variable name="tokenExpiry" value="@{{ return DateTime.UtcNow.AddSeconds((int)context.Variables['tokenResponseJson']['expires_in'] - 60); }}" /> <cache-store-value key="cachedAccessToken" value="@{{context.Variables['cachedAccessToken']}}" duration="@{{(new TimeSpan(0, (int)context.Variables['tokenResponseJson']['expires_in'], 0))}}" /> <cache-store-value key="tokenExpiry" value="@{{context.Variables['tokenExpiry']}}" duration="@{{(new TimeSpan(0, (int)context.Variables['tokenResponseJson']['expires_in'], 0))}}" /> </when> <otherwise> <cache-lookup-value key="cachedAccessToken" variable-name="cachedAccessToken" /> <cache-lookup-value key="tokenExpiry" variable-name="tokenExpiry" /> </otherwise> </choose> <set-header name="Authorization" exists-action="override"> <value>@{{$"Bearer {context.Variables['cachedAccessToken']}"}}</value> </set-header> </inbound> <backend> <base /> </backend> <outbound> <base /> </outbound> <on-error> <base /> </on-error> </policies>
流水线用Bicep代码
resource apim 'Microsoft.ApiManagement/service@2022-04-01-preview' existing = { name: apimName resource apiVersionSet 'api-version-sets@2018-06-01-preview' = if (enableApiVersioning) { name: apiName properties: { displayName: displayName versioningScheme: versionScheme versionHeaderName: 'X-Api-Version' versionQueryName: 'api-version' } } resource api 'apis' = { name: enableApiVersioning ? apiNameVersioned : apiName properties: { displayName: displayName path: '${pathPrefix}${apiName}' format: definitionFormat protocols: [ 'https' ] subscriptionRequired: true value: definition apiVersion: enableApiVersioning ? version : null apiVersionSetId: enableApiVersioning ? apiVersionSet.id : null subscriptionKeyParameterNames: { header: 'Ocp-Apim-Subscription-Key' query: 'subscription-key' } } resource apiPolicy 'policies' = if (!empty(policy)) { name: 'policy' properties: { value: policy } } } }
问题根源与修复
错误是因为XML策略里的表达式语法不符合APIM规范:
- APIM策略表达式必须用
@(...)包裹,你用了@{{ ... }},这种写法会让解析器误判令牌,触发报错。 - 同时原策略里引用命名值的方式不对,无法正确读取APIM中的密码命名值。
修复后的XML策略:
<policies> <inbound> <base /> <choose> <when condition="@(!context.Variables.ContainsKey("cachedAccessToken") || DateTime.UtcNow >= (DateTime)context.Variables["tokenExpiry"])"> <set-backend-service id="apim-generated-policy" backend-id="{0}" /> <send-request mode="new" response-variable-name="tokenResponse" timeout="20" ignore-error="false"> <set-url>{1}/token</set-url> <set-method>POST</set-method> <set-header name="Content-Type" exists-action="override"> <value>application/x-www-form-urlencoded</value> </set-header> <set-body>@($"grant_type=password&username={2}&password={context.Deployment.NamedValues["AmxPassword"].Value}")</set-body> </send-request> <set-variable name="tokenResponseJson" value="@(JsonConvert.DeserializeObject((string)context.Variables["tokenResponse"].Body.As<string>()))" /> <set-variable name="cachedAccessToken" value="@((string)context.Variables["tokenResponseJson"]["access_token"])" /> <set-variable name="tokenExpiry" value="@(DateTime.UtcNow.AddSeconds((int)context.Variables["tokenResponseJson"]["expires_in"] - 60))" /> <cache-store-value key="cachedAccessToken" value="@(context.Variables["cachedAccessToken"])" duration="@(new TimeSpan(0, (int)context.Variables["tokenResponseJson"]["expires_in"], 0))" /> <cache-store-value key="tokenExpiry" value="@(context.Variables["tokenExpiry"])" duration="@(new TimeSpan(0, (int)context.Variables["tokenResponseJson"]["expires_in"], 0))" /> </when> <otherwise> <cache-lookup-value key="cachedAccessToken" variable-name="cachedAccessToken" /> <cache-lookup-value key="tokenExpiry" variable-name="tokenExpiry" /> </otherwise> </choose> <set-header name="Authorization" exists-action="override"> <value>@($"Bearer {context.Variables["cachedAccessToken"]}")</value> </set-header> </inbound> <backend> <base /> </backend> <outbound> <base /> </outbound> <on-error> <base /> </on-error> </policies>
修复要点:
- 把所有
@{{ ... }}替换成@(...),符合APIM表达式语法要求。 - 修正密码命名值的引用方式为
context.Deployment.NamedValues["AmxPassword"].Value,确保能正确读取APIM中配置的命名值。 - 移除不必要的
return语句,简化表达式。
内容的提问来源于stack exchange,提问作者Rob Bowman
相关产品推荐
相关产品推荐

