У меня есть служба приложений Azure, на которой размещена конечная точка OData, которая находится за экземпляром службы управления API Azure (APIM). Чтобы предотвратить вызов службы приложений напрямую, она защищена сертификатом, который есть только у APIM.
Когда я вызываю URL-адрес APIM через Chrome или Postman, он ведет себя так, как ожидалось. Всего один запрос без перенаправлений или забавных дел, и он возвращает корень OData. Вот лог Fiddler запроса к APIM с помощью Postman
Однако при использовании того же URL-адреса в качестве источника OData в Power Query с использованием OData.Feed() он возвращает 301, который перенаправляется на серверный URL-адрес, что, очевидно, не работает, поскольку этот URL-адрес защищен сертификатом. Вот журнал Fiddler запроса к APIM с использованием Power Query в Excel
Я настроил ключ подписки для передачи в заголовках, но я также пробовал его в качестве параметра запроса, и он в любом случае не работает в Power Query. Я также пытался напрямую использовать конечную точку объекта OData (чтобы избежать вызова $metadata), но безуспешно.
Пользовательский агент, который использует Power Query, — это Microsoft.Data.Mashup, но я не нашел никакой документации о его совместимости с APIM, но это не должно иметь значения, верно?
Как обычно, поработав над этим в течение двух дней, я обнаружил ответ сразу после публикации на StackOverflow. Я оставлю этот вопрос на случай, если у кого-то возникнет такая же проблема.
Проблема заключалась в том, что коннектор Power Query автоматически использует ссылки @odata.context для метаданных и ссылки @odata.nextLink для пейджинга. В этих ссылках в качестве узла по-прежнему использовался сайт службы приложений, а не узел APIM.
Таким образом, быстрое редактирование исходящих правил в APIM помогло решить проблему.
<outbound>
<base />
<set-variable name = "backendBaseUrl" value = "@(context.Request.OriginalUrl.Scheme + "://" + context.Request.OriginalUrl.Host.ToString() + context.Api.Path)" />
<find-and-replace from = "@("http://" + context.Request.Url.Host.ToString())" to = "@((string)context.Variables["backendBaseUrl"])" />
<find-and-replace from = "@("https://" + context.Request.Url.Host.ToString())" to = "@((string)context.Variables["backendBaseUrl"])" />
</outbound>
Здесь я должен правила заменить URL-адреса http и https на случай, если некоторые изменения конфигурации.