Over the last few years, I’ve come to rely on Azure App Services very heavily as a host for my APIs. In my most recent project, we created an API layer that accepted some fairly large payloads. By doing such I learned a couple of things about App Services:
- App Services are a great alternative to on-premise solutions using IIS and really delivers on the PaaS promise of removing the worries of having to manage a web server.
- You still have to be at least a little concerned (or at least aware) of the web server.
Obviously this second point seems counter-intuitive to the general value of PaaS solutions expressed in the first point. But believe-it-or-not, buried under all the Azure Platform software and hardware we don’t have to concern ourselves with, lies some of our old familiar friends from the on-prem world. In this case, it is Internet Information Server (IIS) that provides much of the underlying capabilities provided by App Services.
We came across this by creating an API layer that accepted some fairly large payloads in the POSTs. This issue was somewhat difficult to debug at first because the vast majority of the calls into the service worked as expected. And further, it was an HTTP 403 error, implying some kind of access issue. We noticed after some time that it was only the larger requests that were failing. We found out, via Microsoft support, that our issue was due to size throttling that is implemented in IIS–which we never would have guessed as we were using App Services and not IIS and wouldn’t have considered this limitation.
The solution was fairly simple: we had to inform the underlying IIS instance to continue processing even after the threshold is hit. This is done by passing the value “100-Continue” in the Expect header on each request.
But that presented another problem: we couldn’t force all of our API clients to pass a new header for existing (and previously working) interfaces.
Fortunately, we were already using API Management and had a very easy to implement solution. We just needed a policy that attached the appropriate header to every request so the backend (our API on App Services) would work correctly. We added the following inbound policy to “All operations”:
<policies>
<inbound>
<base />
<set-header name="Expect" exists-action="append">
<value>100-continue</value>
</set-header>
</inbound>
... etc.
</policies>
After all that, things continued to work as expected!