Hybrid mobile detection

Events happening in the community are now at Drupal community events on www.drupal.org.
Fidelix's picture

I have a site that I'm using Responsive Design for screens with a width higher than 1023px, with some adjustments for screens up to 1440w.

For screen widths lesser than 1024, I want to serve a mobile version of the site at m.mydomain.com
I know it's not possible to detect screen width server-side, so I've been wondering if a hybrid approach would work:
1. "Select" all mobile browser user agents on nginx.
2. Redirect them to m.mysite.com/screendetect
3. The HTML on this page would have a <META HTTP-EQUIV="Refresh" CONTENT="6; URL=http://m.mysite.com/">
3. Detect the screen width with JS, and if it's higher than 1023, redirect the user to http://mysite.com/, if not, to http://m.mysite.com

I believe some sort of cookie would need to be set on the client, so he can go back and forth on the full site without being redirected.
Comments? Ideas?

Comments

Well

perusio's picture

Hmm. I don't think you can get screen width detection server side unless you use WURFL or similar.

What you can get is a "bridge" from the client to the server, using JS do detect client side and send it to the server. Most server side schemes I've seen rely solely on the User-Agent header.

So my suggestion is to use UA detection and based on that route the request. Of course that doesn't solve the width thing.

An idea:

  1. Load a JS that does screen width detection early on.

  2. Send the response to a location where there's Lua code.

  3. Lua code sets the cookie, redirects to server that handles the requests.

So this is a two step approach:

  1. Detect width and set cookie.

  2. Route request according to cookie value set in 1.

The first part is some Lua code. The second is just using a map directive and an if with a return.

if ($width_mobile) { # <= 1024px
    return 302 http://m.mysite.com;
}

The screen detection part is quite simple and checks for the width cookie if doesn't exist it sets it. If present routes to the proper backend site.
So the screen detection works as "device balancer". Routes requests based on the device capabilities.

Just an idea.

PS: You could use the auth_request module to do this two step approach. This way you could use a PHP script to set the cookie if not comfortable with Lua.

perusio, thanks for chiming

Fidelix's picture

perusio, thanks for chiming in.
Your workflow looks a lot like mine, but has a few extra steps.

I don't think the LUA part is needed here, or PHP, or any "server-side script" to set the cookie.
From what I know, JS can set the cookie just fine, and I don't give a damn about non-js users because the site won't work for them anyway... And the html I proposed would work as a fallback too...

Performance is very, very important on this project so this is an aspect I need to be sure about. Nginx cache needs to remain untouched by the presence of this cookie.
That's one of the things I am unsure of. Does your awesome nginx config check for the presence of any cookies and then bypasses cache like Varnish does? I use a minor fork of your github config in every single project of mine. Big or small. I love it.

PS. I don't understand how the auth_request module would fit in here.

Yes it can

perusio's picture

but you cannot mark the cookie httpOnly then :)

As for auth_request, here's an idea:

location / {
    auth_request_set $route_device $upstream_http_x_route_device;
    auth_request /width-detection;
    #...
    proxy_pass http://$route_device; # requires Nginx version >= 1.1.11
}

location /width-detection {
     internal; # no direct access
    # check capabilites here and return special header
    # make detection request...
}

Of course you can set the cookie on and do a redirect to a location with JS only.
Check this. But your cookie can be modified by the client then. It's just a paranoia issue :)

As for making use of the cache the only cookie it checks is the session cookie. Of course it will cache the cookie. The other option is setting an header and there you can be more choosy and do:

fastcgi_ignore_headers X-Device-Width;
fastcgi_pass_header X-Device-Width;

I'm afraid that JS is not the best option for setting headers. Hence my suggestion of using either Lua or the auth_request module.

Another idea

perusio's picture

to handle the cache issue. Just gloss over the fact that the Cookie is cached. Instead create a JS script that forces a request to a given location (using AJAX) and that triggers a request that updates the cache. Like the idea discussed here.

This is perfectly suited for the embedded Lua module. It's the solution I like the best. There's a decoupling of the cache and the width detection. You still need the HTML meta refresh thing of course or use a setTimeout (my favourite).

It just occurred to me

perusio's picture

that you couldn't care less about the width Cookie being cached. I'm over complicating :) Just use two separate backends and things will flow smoothly.

Of course you have to either check the width in each request or set a refresh/timeout to force a recomputation.

I think I understand your

Fidelix's picture

I think I understand your solution, perusio. Very clever, but IMHO overcomplicated.

First, I think the cookie may be the best choice because I don't want this computation to happen more than once for a user. Ever. Even a month after his first access.
About the cookie, I have nothing to worry about if the user manipulates the cookie. He will have an option to switch from DESKTOP/MOBILE versions of the site anyway...

This link you gave me is very useful, and now, after your comments, the direction I need to follow seems much brighter. Thank you. I hope it helps others as well.

PS. I think this might be a good opportunity to learn LUA, and the best of all, LUA in Nginx. Will give it a thought.

Nginx

Group organizers

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds:

Hot content this week