HTTP filters
Contents
HTTP filters enable pipelined processing of http requests.
Filters
| You may wire a filter into the Site service’s execution pipeline via a Site mapping. |
Filters enable you to step into the request pipeline, and execute code at both request and response of the execution pipeline, possibly intercepting the request directly. Similar to an HTTP function, standalone filters are triggered based on an export.
As such, to make a filter, it must export a filter function:
exports.filter = function (req, next) {
var before = new Date().getTime();
var response = next(req); // next(req) hands over the request to the pipeline and returns the response
var after = new Date().getTime();
log.info((after - before) + 'ms');
return response;
};
export function filter(req, next) {
log.info('Request:' + JSON.stringify(req, null, 2));
const response = next(req); // Continue request pipeline
log.info('Response:' + JSON.stringify(response, null, 2));
return response;
}
Only the documented request and response fields cross the next() boundary. Assigning a property of your own — req.myFlag = true — is not an error, but the field is dropped when the request is handed on, so nothing downstream ever sees it. To pass your own data along the pipeline, use
context.setCustomLocalAttribute(): it stores the value in the current execution, where implementations, response processors and the code after next() in this very filter can all read it back. |
exports.filter = function (req, next) {
if (req.getHeader('X-Auth-Token') !== 'letMeIn') {
// intercept request pipeline
return {
status: 403
}
}
req.headers['Authenticated'] = true;
return next(req);
};
exports.filter = function (req, next) {
req.params = {
param1: 'val', // if param1 was not in the original request it will be added, otherwise the original value will be replaced
param2: null, // remove param2 from the original request
param3: [] // another way to remove a parameter
}
return next(req);
};
Re-routing to another content
A filter reached through a site mapping can change which content is rendered, while the address the visitor asked for stays exactly as it was. Set contentPath on the request before handing it on, and the site service resolves the request against that content instead:
export function filter(req, next) {
if (req.cookies.experiment === 'b') {
// Visitors in the experiment get /mysite/campaign/variant-b,
// still under the /mysite/campaign address they asked for
req.contentPath = `${req.contentPath}/variant-b`;
}
return next(req);
}
This is a rendering re-route, not a redirect: no Location header, no second request, and path, url and the client’s address bar are untouched. Downstream, the request describes the new content — getContent() returns it, and its page or page template is resolved and rendered as though it had been requested directly. Only the target moves, so a re-route cannot leave the current project or branch: the new path is looked up in the same repository and branch, and the site is re-derived from it.
A few things to keep in mind:
-
Pass on the request you were given. Mutate
reqand hand that object tonext(). Building a fresh object instead drops the fields the site service depends on, and the re-route does not take effect. -
The re-routed content’s permissions apply. The lookup itself is privileged, so a filter can target content the visitor cannot read — but the response then fails with
403, as it would have on a direct request. A path that resolves to nothing yields404, naming the path the filter set. -
Mappings are already chosen. Which mappings match is decided before any filter runs, from the originally requested content. A re-route does not re-run that matching, so it neither picks up mappings that would match the new content nor cancels the ones already selected — the remaining filters and any controller mapping in the chain simply receive the re-routed request.
-
Each filter may re-route once, starting from whatever the previous filter passed it. Inside the filter that re-routes, both before and after
next(),getContent()still reports the original content — the change applies to the request handed onwards.
| Build the new path from values you control rather than interpolating a query parameter straight into it — a content path is a lookup key, and path segments have their own validation rules. |