Skip to content
This repository has been archived by the owner on Sep 5, 2023. It is now read-only.

Device detection #5

Open
barnese3 opened this issue Dec 19, 2018 · 6 comments · May be fixed by #39
Open

Device detection #5

barnese3 opened this issue Dec 19, 2018 · 6 comments · May be fixed by #39

Comments

@barnese3
Copy link
Contributor

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
        }
}
@mrkurt
Copy link
Member

mrkurt commented Dec 26, 2018

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.

@mrkurt
Copy link
Member

mrkurt commented Dec 26, 2018

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

@barnese3
Copy link
Contributor Author

barnese3 commented Jan 2, 2019

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.

@mrkurt
Copy link
Member

mrkurt commented Jan 2, 2019

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));

@mrkurt
Copy link
Member

mrkurt commented Jan 2, 2019

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

@mrkurt mrkurt changed the title Device-based caching at the Edge Device detection Jan 2, 2019
@barnese3
Copy link
Contributor Author

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.

@barnese3 barnese3 linked a pull request Jan 26, 2019 that will close this issue
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants