Device detection
Feature: device-based caching/dynamic serving
-Using the User-Agent header from requests to deliver cached content based on device type
import { responseCache } from '@fly/cache'
fly.http.respondWith(async function(req) {
// use "vary: user-agent" header to tell Google that you’re tailoring the content to the User Agent
req.headers.set("Vary", "User-Agent")
// get user device type
let type = req.headers.get("User-Agent").toLowerCase()
// serve cached or new response based on device type
if (type.includes("macintosh")) {
let c = cache("mac", "Hi Mac user!")
return c
} else if (type.includes("windows") && !type.includes("mobile")) {
let c = cache("windows", "Greetings desktop Windows user!")
return c
} else if (type.includes("iphone")) {
let c = cache("iphone", "Howdy iPhone user!")
return c
} else if (type.includes("android" && "mobile")) {
let c = cache("android", "Cheers mobile Android user!")
return c
} else {
let c = cache("device unknown", "Welcome user!")
return c
}
})
async function cache(key, response) {
// create a unique key
let cacheKey = `${key} version of www.example.com`
// get cached response if there is one and serve it
let cachedValue = await responseCache.get(cacheKey)
if (cachedValue) {
console.log("response served from cache at key: ", cacheKey)
return cachedValue
} else {
// serve new response and add it to the cache
let deviceResponse = new Response(response)
await responseCache.set(cacheKey, deviceResponse)
return deviceResponse
}
}
Ok so here's what I'd suggest for this. Rather than doing caching, exactly, make a device based segmentation middleware (like the cookie one here: https://github.com/superfly/cdn/blob/cookie-segments/src/middleware/cookie-segments.ts).
That basic model can be used to route people to two different origins, or even trigger other middleware like metrics / reporting.
When we get into caching more, we can make this + other stuff cache aware.
Also I haven't looked closely at this library, but User Agent parsing is so intricate it might be worth using it (or something like it): https://github.com/faisalman/ua-parser-js
Ok so would something like this be a better example maybe?
import proxy from '@fly/proxy'
fly.http.respondWith(async function(req) {
const parser = require('ua-parser-js')
const ua = req.headers.get("User-Agent")
const uaObj = parser(ua)
const deviceType = uaObj.device.type
if (deviceType === "mobile") {
console.log("mobile")
const app = proxy("http://mobile.example.com/")
return app(req)
} else if (deviceType === "tablet") {
console.log("tablet")
const app = proxy("http://tablet.example.com/")
return app(req)
} else {
console.log("desktop")
const app = proxy("http://www.example.com/")
return app(req)
}
})
This uses the https://github.com/faisalman/ua-parser-js library to detect the user’s device and then routes to different origins based on the device type.
That seems like a good path. We haven't documented this well yet, but we're shooing for apps that use the CDN code and look something like this:
import { proxy, pipeline } from "@fly/fetch";
import { middleware } from "./src/";
const origin = proxy("https://example.com");
const app = pipeline(
middleware.httpsUpgrader,
middleware.responseHeaders({ "powered-by": "caffeine"})
);
fly.http.respondWith(app(origin));
To route by device type, it could work like this:
import { proxy, pipeline } from "@fly/fetch";
import { middleware, userAgent } from "./src/";
const backends = {
mobile: proxy("https://mobile.com"),
default: proxy("https://example.com")
};
const origin = devices.route(
userAgent.mobile(backends.mobile),
backends.default
);
const app = pipeline(
middleware.httpsUpgrader,
middleware.responseHeaders({ "powered-by": "caffeine"})
);
fly.http.respondWith(app(origin));
A simpler example might just add device-type to the request headers, too:
import { proxy, pipeline } from "@fly/fetch";
import { middleware, userAgent } from "./src/";
const origin = proxy("https://example.com")
const app = pipeline(
middleware.httpsUpgrader,
userAgent.addDeviceHeaders,
middleware.responseHeaders({ "powered-by": "caffeine"})
);
fly.http.respondWith(app(origin));
Here's an example middleware to add a device type header in a branch: https://github.com/superfly/cdn/compare/user-agent-parsing?expand=1#diff-56064ccff3c2d3c1065db991c8672487
In progress: working on middleware that handles deep linking to apps on mobile devices. It will use the user-agent header from requests to determine the user's device and OS. If user is on mobile Android, they will be routed to Google Play Store to download the app. If user is on mobile iOS, they will be routed to Apple App Store to download the app.