Why is Azure APIM preflight response so slow? - azure

I have an app service which is accessed via APIM.
Intermittently (about 1/5), HTTP responses for GET requests are taking >1 minute.
I noticed the preflight request is taking 1.4 minutes, which makes me think there is nothing wrong with the application itself, but rather with APIM.
I've confirmed that there is nothing DB related that is causing the slowness.
I have this policy set up in the API.
Does this mean the preflight request is being responded to by APIM, and not the backend web service?
<inbound>
<cors>
<allowed-origins>
<origin>*</origin>
</allowed-origins>
<allowed-methods>
<method>*</method>
</allowed-methods>
<allowed-headers>
<header>*</header>
</allowed-headers>
</cors>
<base />
</inbound>
Here is the preflight request:
And the timing:
Here's the actual request:
And the timing:
I've replicated this slowness using Chrome with disabled security settings:
"C:\Program Files\Google\Chrome\Application\chrome.exe" --disable-web-security --ignore-certificate-errors --user-data-dir="C:/ChromeDevSession"
in order to avoid the preflight request, however the response still takes about 1.4 minutes.
So the preflight request itself is not causing slowness.
I've tested the exact same request through the APIM test tab and am unable to replicate the slowness.
We have other app services running which are not behind APIM and they run fine, which is why I believe the issue is APIM.
However I'm very confused as to why I can't replicate the issue within the APIM test tab in the Portal (I've tried 100 times).
The only difference between the requests is that I've left out the Connection: keep-alive header in APIM because it was causing a 500 response.
Here's the pricing tier info:
Why is APIM intermittently slow and why is it only experienced through the web browser and not through the APIM test tab in the Portal?

Related

Can't do a websocket handshake using an APIM on azure

I have some issues doing a handshake to a websocket endpoint through an Azure APIM. This error doesn't happen if I use the app service endpoint, it is only when the request is sent through the APIM.
The main problem, and as far I can see, is that the APIM is not sending the header Connection: Update, it overrides the header and sets it to keep-alive. I have tried to create a policy to set that header to Upgrade but the APIM returns the following error.
Error in element 'set-header' Header name is invalid or restricted
from modification
The policy I tried to use is
<policies>
<inbound>
<base />
<set-header name="Connection" exists-action="override">
<value>Upgrade</value>
</set-header>
</inbound>
...
</policies>
I opened an issue on the MS documentation github (https://github.com/MicrosoftDocs/azure-docs/issues/96878) asking this and they told me to try using some extra headers
Connection: Upgrade
Upgrade: Websocket
Sec-WebSocket-Version: 13
And the response is the same in any case...
{
"statusCode": 400,
"message": "Invalid websocket upgrade request"
}
Postman request and response
Also, there is another parameter negotiateVersion that is set to 1 that can't be seen on the picture.
Any way to solve this? Thanks in advance.

CORS - Enabled localhost origin on Azure API Management, but still receiving error

I'm trying to test retrieving data from my teams API that is configured via Azure API Management. I'm local hosting the client web app (a create-react-app project) that will be making calls to the API, and enabled CORS policies for my localhost origin in APIM.
I've added the inbound policies for All Operations in APIM:
I call the api using the same headers and method that's enabled in the CORS policy.
Yet I still get hit with the "No 'Access-Control-Allow-Origin' header is present on the requested resource."
I don't want a use a plugin since that doesn't really solve the large problem, and I can't use a wildcard because 'Allow-Credentials' must be set to true.
I've looked at so many versions of this question and nothing has helped. Does anyone know what I might be missing?
Restating derpirscher's answer for others: I needed to add Options to the allowed method because a preflight Options request is sent:
<cors allow-credentials="true">
<allowed-origins>
<origin>http://localhost:3000</origin>
</allowed-origins>
<allowed-methods>
<method>GET</method>
</allowed-methods>
<allowed-headers>
<header>content-type</header>
<header>accept</header>
<header>authorization</header>
<header>options</header>
</allowed-headers>
</cors>

Why don't I see any results when I run my test on Azure API Management

I signed up for an API that retrieves a zip file and downloads it. For this, I received a bearer token.
I have created an apim instance and was looking to test the API I had subscribed to which downloads the file.
When I tested it, the apim instance kept loading and got stuck.
I tested this on Postman and it works perfectly. I got the "200 OK response", but still got weird characters like "�vt�" in my body, but that's probably because I'm retrieving a zip file. But why doesn't it work also within Azure's apim? Are there any extra policies I need to add?
Kind regards
You got the "200 OK response", but still facing the issue, you can try to troubleshoot by following approach:
1. If Backend section is taking most of the time (approx. 5 seconds), which means there is some slowness or long running operation is taking place at the backend.
Once you have isolated that the slowness is at the backend, you need to investigate the backend application code of the Web API application. For scenarios where you don't have access to the backend, you can implement caching at APIM level like below. Read about how you can implement caching policies to improve performance in Azure API Management.
<?xml version="1.0" encoding="UTF-8"?>
<policies>
<inbound>
<base />
<cache-lookup vary-by-developer="true" vary-by-developer-groups="true" must-revalidate="true" downstream-caching-type="public" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
<cache-store duration="60" />
</outbound>
<on-error>
<base />
</on-error>
</policies>
You can refer to REST API service when called from azure APIM returning empty response body with Status code 200,
Azure API Management returning 200 status without response body, gzip Compression, and Azure API management gives 200 response code,

Azure API Management forward-request Not Honoring follow-redirects

I have an Azure API Management with the following backend policy:
<backend>
<forward-request timeout="10" follow-redirects="true" />
</backend>
When testing in Postman, I'm still receiving a 308 Permanent Redirect. I thought that follow-redirects followed a backend redirect response. Why is it getting passed back to the client?
follow-redirects:Specifies whether redirects from the backend service are followed by the gateway or returned to the caller.
As the article said, when you follow-redirects as true, it will returned to the client.

CORS Preflight request not working with Azure API Management

I have 2 Azure Websites (ASP.NET MVC 5 and ASP.NET WebApi 2). The MVC website has some jQuery which tries to post CORS request to the WebApi. It works just fine if it connects directly to the WebApi. However it doesn't work when trying to connect through the API Management.
The error I got in Chrome is:
XMLHttpRequest cannot load https://XXXXXX.azure-api.net/api/search. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://YYYYYY.azurewebsites.net' is therefore not allowed access.
I ruled out the problem being with the WebApi config, because as I said it works directly.
Below is my policy:
<policies>
<inbound>
<cors>
<allowed-origins>
<origin>*</origin>
<!-- allow any -->
</allowed-origins>
<allowed-headers>
<header>accept</header>
<header>accept-encoding</header>
<header>access-control-request-headers</header>
<header>access-control-request-method</header>
<header>connection</header>
<header>content-type</header>
<header>host</header>
<header>origin</header>
<header>referer</header>
<header>user-agent</header>
</allowed-headers>
<expose-headers>
<header>access-control-allow-headers</header>
<header>access-control-allow-origin</header>
<header>cache-control</header>
<header>content-length</header>
<header>date</header>
<header>expires</header>
<header>pragma</header>
<header>server</header>
<header>set-cookie</header>
<header>x-aspnet-version</header>
<header>x-powered-by</header>
</expose-headers>
</cors>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
</policies>
Any ideas?
CORS policy intended use is for the cases when your backend does not support CORS. In that case you can put this policy in and it will reply to OPTION requests without forwarding them to your backend. And you can use this policy to decide which origins/headers/methods to process for CORS.
Alternatively, if your backend already supports CORS and you see no benefit in handling CORS flow on APIM level you could just proxy the entire flow. For that to happen you should remove CORS policy and create a new operation in your API in APIM with OPTIONS method, so that OPTIONS requests would be forwarded to backend normally.
After spending many weeks fighting this issue, and coming up empty, I (with the help of Microsoft Support) discovered a bug in Azure API Management. If you have multiple APIs and one of them does not have an URL suffix (even if it's not the one that's failing), check it's CORS policy. The first API we put in Azure API Management didn't have any methods other than GET, so we set a CORS policy to only allow GET and OPTION. However, the bug that exists seems to make all inbound pre-flight requests route to the API without an URL suffix. So I was able to fix my issue by added a PUT (and POST for good measure) to the CORS policy of an unrelated API.
TL;DR: Check to make sure the CORS policy of the API with no URL suffix allows the method that's failing.
Hope this saves someone's sanity.
I was getting below preflight error from APIM and found that issue is that my policy <method>*</method> is actually not working. Changing the policy to explicitly add all the HTTP Verbs like below has resolved my issue.
<allowed-methods preflight-result-max-age="300">
<method>OPTIONS</method>
<method>GET</method>
<method>POST</method>
<method>PUT</method>
<method>PATCH</method>
<method>DELETE</method>
</allowed-methods>

Resources