KittenRouter is a routing script for Cloudflare Workers that attempts to connect to a list of specified servers and redirect the request to whichever server that is currently 'alive' at that point of time. It is extremely useful when you have servers that may go down or are unavailable to process the request and KittenRouter can automatically attempt to redirect the request to the next configured URL for processing.
At the same time, it can be configured to log down information to your ElasticSearch server for analytical purposes. Some of the information logged are the status of the servers, country of the request and etc. For the full details, see the index.js
file.
Ultimately, KittenRouter is used together with Cloudflare workers. There are two ways in which you can use KittenRouter on your Cloudflare worker script,
- Using NPM modules
- Adding KittenRouter manually
If you are comfortable in building projects in NodeJS and wanted to deploy it serverlessly on Cloudflare, you can do that as well.
You can use NPM modules in Cloudflare, like how we did for Inboxkitten API component, just that you will need webpack to help compact your scripts into a single .js
file and this single .js
file will be used in your Cloudflare worker.
Similarly, if you want to use KittenRouter on your Cloudflare script, you can just follow the 7 steps below to achieve it.
KittenRouter is published in npm repository and you can install it as an NPM module.
# Change to your project directory
$ cd <to your project>
# Install kittenrouter
$ npm install --save kittenrouter
# Install webpack, we will need it to compact all your files into a single js file
$ npm install --save webpack
After installing KittenRouter, you can simply create a variable and use it immediately. You can store this script as your entrypoint script such as index.js
.
const KittenRouter = require("kittenrouter");
let config = {
// some configuration that you have for your KittenRouter
};
let kittenrouter = new KittenRouter(confg);
// Usual Cloudflare worker script
addEventListener('fetch', event => {
event.respondWith(handleFetchEvent(event))
})
// the async function to handle the request
async function handleFetchEvent(event) {
// Depends on your logic of how you want to handle the request
// E.g. only GET requests will need to go through KittenRouter
let req = event.request;
if (req.method === "GET") {
return kittenrouter.handleFetchEvent(event);
}
// Default behavior
return await fetch(event);
}
At this point, we can create a run command so that we can run it easily. In your package.json
file, add in
{
// other settings...
"scripts": {
// other settings...
"build-cloudflare": "webpack --mode production index.js"
// other settings...
},
// other settings...
}
One thing to note in webpack is that we can specify the environment the Javascript code will be run in. webworker
is the closest environment to Cloudflare Workers environment. So in your webpack.config.js
, configure the target to point to webworker
.
module.exports = {
target: 'webworker'
};
In your webpack.config.js
, add in
module.exports = {
target: 'webworker',
optimization: {
// We no not want to minimize our code.
minimize: false
}
}
$ npm run build-cloudflare
Step 6
should create a main.js
inside the dist
folder, you can then copy the entire main.js
and paste into your Cloudflare Worker's Editor of your domain.
Given that you have a Cloudflare worker script such as
// Usual Cloudflare worker script
addEventListener('fetch', event => {
event.respondWith(handleFetchEvent(event))
})
// the async function to handle the request
async function handleFetchEvent(event) {
// Default behavior
return await fetch(event);
}
You can then add the entire KittenRouter
class, which is basically the index.js
file in this github project into your script
// methods of KittenRouter ...
// ...
class KittenRouter {
// ...
}
// Usual Cloudflare worker script
addEventListener('fetch', event => {
event.respondWith(handleFetchEvent(event))
})
// ...
let config = {
// some configuration that you have for your KittenRouter
}
// methods of KittenRouter ...
// ...
class KittenRouter {
// ...
}
// Usual Cloudflare worker script
addEventListener('fetch', event => {
event.respondWith(handleFetchEvent(event))
})
// ...
Declare the KittenRouter object and use it in your request process function. You can then deploy this script to your Cloudflare Worker.
let config = {
// some configuration you have for your KittenRouter
}
// methods of KittenRouter ...
// ...
class KittenRouter {
// ...
}
// Usual Cloudflare worker script
addEventListener('fetch', event => {
event.respondWith(handleFetchEvent(event))
})
// Initialize a new KittenRouter object
let kittenrouter = new KittenRouter(confg);
// the async function to handle the request
async function handleFetchEvent(event) {
// Depends on your logic of how you want to handle the request
// E.g. only GET requests will need to go through KittenRouter
let req = event.request;
if (req.method === "GET") {
return kittenrouter.handleFetchEvent(event);
}
// Default behavior
return await fetch(event);
}
KittenRouter is initialized with a configuration map that contains the routes and log server settings attributes.
Attribute | Description |
---|---|
route | An array of servers' url for the KittenRouter to connect to. KittenRouter will attempt to access the urls in the order of the array that was set. |
log | A map that contains the settings for your ElasticSearch server |
disableOriginFallback | Set to true to disable fallback to origin host when all routes fails |
A sample of the configuration map looks like this
//
// Routing and logging options
//
module.exports = {
// logging endpoint to use
log : [
{
// Currently only elasticsearch is supported, scoped here for future alternatives
// One possible option is google analytics endpoint
type : "elasticsearch",
//
// Elasticsearch index endpoint
//
url : "https://<Your elasticsearch server url>",
//
// Authorization header (if needed)
//
basicAuthToken : "username:password",
//
// Index prefix for storing data, this is before the "YYYY.MM" is attached
//
indexPrefix : "test-data-",
// Enable logging of the full ipv4/6
//
// Else it mask (by default) the last digit of IPv4 address
// or the "network" routing for IPv6
// see : https://www.haproxy.com/blog/ip-masking-in-haproxy/
logTrueIP : false,
// @TODO support
// Additional cookies to log
//
// Be careful not to log "sensitive" cookies, that can compromise security
// typically this would be seesion keys.
// cookies : ["__cfduid", "_ga", "_gid", "account_id"]
}
],
// Routing rules to evaluate, starting from 0 index
// these routes will always be processed in sequence
route : [
// Lets load all requests to commonshost first
"commonshost.inboxkitten.com"
// If it fails, we fallback to firebase
//"firebase.inboxkitten.com"
],
// Set to true to disable fallback to origin host
// when all routes fails
disableOriginFallback : false,
}