JSON Proxy Using IIS Reverse Proxy for Fun and Profit
Developing mobile applications using Sencha Touch that will be packaged up using PhoneGap to run as a “native” app on a phone can be a bit of a pain. Especially if you’re accessing some kind of API. Because of restrictions in the browser, you’re not allowed to do cross site requests, meaning it’s difficult to call external API’s during development. You’re likely to run your new shiny mobile app from a file on your hard drive or served up by a locally running web server. But the API’s you need to access are probably running on a another external server. Hitting that API will give you a sad message from Chrome, because of the “Same Origin Policy”. Safari will just return nothing, and ignore you. IE9 and Firefox are not even options, because they don’t run WebKit. You can of course do all of your development in PhoneGap, deploying to an emulator or a real device and always test on that. But it adds quite a bit of time to the feedback loop and for prototyping it’s especially nice to have the fast feedback loop afforded by the browser, the console and the inspector. So how do we get around this annoyance. One way is to use JSON-P and the ScriptTagProxy. Another is to utilize a reverse proxy server, which is what I’ll describe in this post.
I’m developing on Windows 7, so this is a description on how to set it up using IIS. This guide on the IIS.net website explains things in more detail. If you’re running on Mac or Linux you could setup nginx, Apache or another web server. Most web server software include proxy rewrite and reverse proxy capabilities.
Before we get started here’s a quick and simple diagram of what we’re trying to achieve:
Browser < => Local Web Server (IIS) Proxy To => External Server with API
First you’ll want to install the Application Request Routing module. This module works with the URL Rewrite module to proxy requests back and forth between your web server and some other back end server. Next step is to enable the ARR module on your IIS Root.
Then on your web site that hosts your mobile application code (basically just a virtual directory to your web root of your Sencha Touch application) you want to configure the URL Rewrite module. There are a couple of options for doing this, one is through the IIS Management GUI, the other is by adding the appropriate configuration in your web.config file. I’ll list the configuration settings in the following, but you can just as well set this up using the GUI and the guide. Another options is to copy in the following configuration settings, and then tinker with it using the GUI afterwards. The IIS Manager GUI is basically a nice way of manipulating web.config files.
If your virtual directory doesn’t have a web.config (it probably doesn’t since it’s serving up plain HTML and JS) create a new file called web.config and fill in the following:
<?xml version="1.0" encoding="UTF-8"?> <configuration> </configuration>
Then add the following in between the configuration-tags, so your entire file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Proxy To External server" stopProcessing="true">
<match url="^services/(.*)" />
<conditions>
</conditions>
<action type="Rewrite" url="http://my-external-server.com/{R:0}" logRewrittenUrl="false" />
</rule>
</rules>
<outboundRules>
<rule name="Add Application prefix" preCondition="IsHTML">
<match filterByTags="A" pattern="^/(.*)" />
<conditions>
<add input="{URL}" pattern="^/(appName)/.*" />
</conditions>
<action type="Rewrite" value="/{C:1}/{R:1}" />
</rule>
<preConditions>
<preCondition name="IsHTML">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
<urlCompression doStaticCompression="false" />
</system.webServer>
</configuration>
This configuration says to rewrite all requests coming into the virtual directory at http://localhost/appName/services/ to http://my-external-server.com/services/. The outbound rule looks at the returned HTML and rewrites that too, so links and hrefs will continue to work. If you don’t do this step, links won’t be rewritten and when you follow them you’ll get an error because the links point to the server you’re trying to mask.
With this in place you can configure your Sencha Touch data classes to use http://localhost/appName/services/ as the server prefix, and service calls will be proxied back and forth to your external data server. To make it easier to transition from development to production, wrap the server prefix in a configuration object.
I’ve found this proces to be of tremendous value when developing. It’s so much easier to debug things when they run in the browser and you can use the full browser stack.
One thing I’ve found is that sometimes IIS will barf and throw an internal server error related to request compression and GZip’ping. I’ve disabled Static Compression in the hope that that would help, which it does. The error still shows up though. I’ve found that a quick “iisreset” does the trick and puts everything back on the track. This minor annoyance is worth it compared to the added benefit of running everything in the browser and skipping an emulator.
If you like my writing you should subscribe to my RSS feed.
Sencha Touch: Each picker slot is required to have a name
I was using a select field in Sencha Touch. When running in Chrome it worked fine, and I could open it and select a value. Deploying it via PhoneGap to an Android phone showed that it didn’t work. Instead I got this error in the “adb logcat” output:
D/PhoneGapLog( 2323): file:///android_asset/www/lib/sencha/sencha-touch-debug.js
: Line 25587 : Error: Each picker slot is required to have a name.
E/Web Console( 2323): Error: Each picker slot is required to have a name. at fil
e:///android_asset/www/lib/sencha/sencha-touch-debug.js:25587
Obviously the error message hold the key: namely that the select field needs to have a name. Giving it one, makes the error go away. Still interesting that it works OOB in Chrome. I guess Chrome auto-generates a name for the field and the Android browser doesn’t.
If you like my writing you should subscribe to my RSS feed.
I am a self employed independent software development consultant at