Web site exhibits JavaScript error on iPad / iPhone under 3G but not under WiFi
Asked Answered
L

2

24

Connecting to http://www.manage-us.com on an iPad under 3G [used to] result in a JavaScript error which can be seen if the developer console has been enabled. If the same page is accessed using the same iPad under a WiFi connection no error is displayed. [The error has now gone because I applied the fix below!].

Why is this?

I've tried simulating low bandwidth (using dummynet) on Safari on Mac and on the iPad simulator on Mac. This does not reproduce the problem.

I am currently suspecting this is a problem being introduced by my mobile operator in the UK (O2) which is known to modify some content through a proxy cache such as downgrading image files. If you can confirm that you don't experience this problem when connecting by 3G on iPad or iPhone through another mobile operator that would be helpful.

Leela answered 19/7, 2010 at 15:18 Comment(5)
Does the iPad change User agent string based on connection type? Perhaps the server is serving up different pages accordingly?Romina
"A Javascript error" - care to elaborate?Janenejanenna
The current error is: "ReferenceError: Can't find variable: liftAjax". I previously had Google Analytics code on the page and a different JavaScript error relating to unterminated comments manifested itself within the included ga.js code. (but only when connecting by 3G)Leela
It's now back to showing an onscreen error within the ga.js code.Leela
Just to be clear - the website no longer exhibits an error because I applied the fix below. Also of interest is another independent case of the same issue: oh7lzb.blogspot.com/2010/07/…Leela
L
34

I've investigated this further and discovered that the problem is that the UK mobile operator O2 (the original exclusive iPhone operator for Apple), modifies web content before sending it to iPhones and iPads. Probably before sending it to any device running a mobile browser.

They non-deterministically inline some of the CSS and JavaScript into the main source files of the web pages. This can create errors either because of mistakes in their algorithm or the consequence of stripping white space from source files with syntactic mistakes in the source files which were otherwise benign.

These modifications also strip copyright messages from copyrighted javascript libraries and css libraries and play havoc with delivery optimisations.

For example, imagine if a user is visiting a sequence of pages on your site which all link to jQuery libraries. Instead of letting your mobile browser locally cache the library, O2 inline the library on every page, forcing your phone to load the entire library over and over again for every page.

I've written a blog about the issue here in the hope if drawing a bit more attention to this: http://stuartroebuck.blogspot.com/2010/07/mobile-proxy-cache-content-modification.html

My workaround is to use document.write() to insert the JavaScript library dependencies at load time and prevent O2 from inlining them. This seems to work quite well. e.g.:

<script type="text/javascript">
// <![CDATA[
// Using document.write to load JavaScript dependencies to bypass O2 network inlining of JavaScript.
function loadJS(file){document.write("<" + "script type='text/javascript' src='" + file + "'></" + "script>")}
loadJS("/js/jquery-1.4.2.min.js");
loadJS("/js/myJSLibrary.js");
// ]]>
</script>

Note that, as ever, document.write will not work if the page is served as XHTML.

Leela answered 20/7, 2010 at 16:43 Comment(9)
Well-spotted. I’d noticed that O2 compress sites when served over 3G (it happens when I use tethering on my iPhone as well), but I didn’t realise they sometimes caused JavaScript errors. I’ve contacted them about this; fingers crossed they’ll fix the issue on their end at some point.Equipage
@Paul - Did O2 come back to you about this? I just ran into the same problem using jQuery on a website it made and it breaks it. Any feed back from them? Probably ignored you didn't they...Eutrophic
@ppumkin: As far as I can see from my e-mail record, I got an automated acknowledgement from O2 Customer Service on the 21st July 2010, but didn’t hear back after that. (It’s possible I got a reply and deleted it, or got it via another medium, but I wouldn’t have thought so.)Equipage
@Paul - Thanks- I have been getting mixed results. It seems like if you specify <!DOCTYPE ..... XHTML 1.0 ... > then it loads all the inline stuff as usual- but nothing breaks. Without that it does not escape any character and breaks the page.I tried this using a new o2 Dongle POSTPAY and tethered via bluetooth from nokia 61xx PREPAY APN.Eutrophic
@ppumkin: did you see sroebuck’s blog posts on this issue? There’s a good summary here: stuartroebuck.blogspot.com/2010/07/…Equipage
@ppumkin: and a workaround here: stuartroebuck.blogspot.com/2010/08/…Equipage
Yea brilliant! I thought there was going to be something with the http header :) ThanksEutrophic
@PaulD.Waite Thanks for this. They are still at it 5 years laterRendarender
@calumbrodie: well if it ain’t broke, don’t fix it. Also maybe don’t fix it if it is broke apparently.Equipage
V
1

For anyone needing a solution to this in ASP.NET, this sets the Cache-Control header as per http://stuartroebuck.blogspot.com/2010/08/official-way-to-bypassing-data.html for javascript files using URL Rewrite Module 2.0 http://learn.iis.net/page.aspx/665/url-rewrite-module-20-configuration-reference.

<system.webServer>
        <rewrite>
            <outboundRules>
                <rule name="Compression header" preCondition="Match JS Files">
                    <match serverVariable="RESPONSE_Cache-Control" pattern="(.*)" />
                    <action type="Rewrite" value="no-transform" />
                </rule>
                <preConditions>
                    <preCondition name="Match JS Files">
                        <add input="{RESPONSE_CONTENT_TYPE}" pattern="(javascript)$" />
                    </preCondition>
                </preConditions>
            </outboundRules>
        </rewrite>

Alternatively can be done using a HttpModule

public class AddHeaderModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.EndRequest += OnEndRequest;
    }

    void OnEndRequest(object sender, System.EventArgs e)
    {
        if(HttpContext.Current.Response.ContentType.Contains("javascript"))
            HttpContext.Current.Response.Headers.AddHeader("Cache-Control", "no-transform");
    }
}

and

<configuration>
   <system.web>
      <httpModules>
         <add name="AddHeaderModule" type="your.namespace.AddHeaderModule" />
      </httpModules>
   </system.web>
</configuration>
Vermiculation answered 9/2, 2012 at 13:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.