Apple officially prevents
http requests in iOS apps since January 2017 through the App Transport Security (ATS) protocol. Although ATS has been around for a little while now, it was still possible to set domain exceptions in your app and allow
http requests to these domains only. However, as of January 2017, this is no longer feasible and all
http requests are blocked. We can all agree that this is a good cause and improving the security of our apps should be a top priority to all of us, but it does cause some concern in cases where loading
http resources is necessary.
For instance, in a previous project, our iOS app had to load pictures from real estate websites that did not support
https. Suddenly - after the January deadline - the app was displaying broken image links for all these resources that were previously loaded through
http. As I had no control over these 3rd party services that were serving their website - and pictures - over
http instead of
https, I had to find another way around this.
The solution that I implemented involved proxying these
http requests through our API, which obviously supported
https. That meant that all
http requests for static resources would instead go through our Node.js server over https, which would fetch the resource through http, and then return the result to the iOS app. Here's what the flow looks like when loading an
http image, for instance,
- Because this is an
httpurl, the iOS app makes a call to the backend instead of fetching the image directly. The url will be:
- The backend server will extract the requested url from the query string (
- The backend will make the
httprequest to that link and will pipe the result directly back to the client.
- The iOS app receives the image as a response to its original
httpsrequest, which respects the ATS protocol and is therefore not blocked by Apple.
In Node and Express, the code looks as follow:
- Route for the backend endpoint:
This tells Express to call the
communicationController.proxyRequests method when the route
/api/v1/proxy is hit.
proxyRequestsmethod, which is very simple and uses the
var proxiedUrl = req.query.link || req.url; request(proxiedUrl).pipe(res); }
This retrieves the requested url from the query string (
req.query.link), and uses the original url only if that doesn't exist.
That's all there is to proxying
http requests! Surprisingly little code to get it done, right?
Although I highly suggest that you use
https everywhere, I hope this helps you get around a nasty use case where you must absolutely use
http, like it helped me.
Let me know what you think and if you found other ways around this.