A simple web server, implement http module(filter) and handler(servlet), autorecover persistent session


A simple web server, implement with filter and handler.

  • Filter (Middleware): A request will try to match all the filters first.
  • Handler: When a request matched a handler, it will returned, only one handler will be executed.
  • Session: By config sessionDir, you can store session in files, with JSON format
  • File: Support uploading files
  • Cache: Cahce template in release mode
npm install websvr

It's simple to start the websvr.

//import WebSvr module
var WebSvr = require("websvr");

//Start the WebSvr, runnting at parent folder, default port is 8054, directory browser enabled;
//Trying at: http://localhost:8054
var webSvr = WebSvr({
    home: "./web"
  , listDir:  true
  , debug:    true
  , sessionTimeout: 60 * 1000

Session based authentication, basically useage:

Session support; 
webSvr.filter(function(req, res) {
  //Link to next filter
}, {session:true});

* filter equal to use
webSvr.use('/home', function(req, res) {
  //do sth.

Filter all the requests that begin with "test/", check the user permission in session, except the "index.htm" and "login.do".

Session Filter: protect web/* folder => (validation by session);
webSvr.filter(function(req, res) {
  //It's not index.htm/login.do, do the session validation
  if (req.url.indexOf("login.htm") < 0 && req.url.indexOf("login.do") < 0 && req.url !== '/') {
    var val = req.session.get("username");

    console.log("session username:", val);
    !val && res.end("You must login, first!");

    //Link to next filter
  } else {
}, { session: true });

Handle Login and put the username in session

Handler: login.do => (validate the username & password)
  username: admin
  password: 12345678
webSvr.url equal to webSvr.get/webSvr.post/webSvr.handle
webSvr.url("login.do", function(req, res) {
  var qs = req.body;
  if (qs.username == "admin" && qs.password == "12345678") {
    //Add username in session
    var session = req.session.set("username", qs.username);
  } else {
    res.end("Wrong username/password");
}, 'qs');

Filter and Handler doesn't have the same match rules when you sending a request

Filter : Match any section in the request url, for example

websvr.filter(".svr", cb);

The result is

request: "domain.com/admin/root/login.svr"   match: true

Handler : Match from the begining (ignore the first '/'), etc:

websvr.handle("root/login", cb)   //equal to
websvr.handle("/root/login", cb)


request: "domain.com/root/login.svr"         match: true
request: "domain.com/admin/root/login.svr"   match: false

You can use regular expression to match any part of url in Handler.

//get cookie value by key

Render template with params, using doT template engine

res.render([view, model]);

View is optional, it will get the location of template from req.url

res.render({json: true});

View is a relative path, relative to web home

//means related to Setting.home
res.render("list.tmpl", {json: true});

View is a absolute path, relative to web root

//means related to Setting.root
res.render("/list.tmpl", {json: true});

Render raw HTML views

res.renderRaw(viewContent, model);

You can change template engine,


for example:


You can define some default properties in model, for example header/footer, this parameters will be overridden if they have the same key in your custom model.

    title   : "WebSvr Page"
  , username: "WebSvr"

You can use template and render it by using websvr.render(tmplPath, model, callback), tmplPath relative to webSvr.home;

//pre-defined model
var model = {};

//render a template using model, callbak argument is result html
webSvr.render("header.tmpl", {categoryList: category.categoryList}, function(html) {
  //store rendered html to header
  model.header = html;

Include file, you can using "#include" to include a file during rendering a template, in order to make the process easier, the file will fetched from the cache pool so the first refresh will not work when you first start the server;

###Be ware: include file: relative to web home, not the template file itself.###

<div id="articles" class="container home">

Cache templates, by default, server will cache the templates(include the "include file" in the templates), turn it off via:

var webSvr = WebSvr({
  templateCache: false

Clear the cached templates


Enable template engine and '', using: res.render()/res.render(model)/res.render(tmplPath, model), etc

webSvr.url(['login.htm', 'setting.htm'], function(req, res) { res.render(); });

It also support include file in include files, but you need to refresh more times after the first running.

Return configuration of current WebSvr instance


Settings API:

var Settings = {
  //home folder of web
  home: "../"

  //http start
  //default port of http
  , port: 8054

  //default port of https
  , httpsPort:  8443
  , httpsKey:   ""
  , httpsCert:  ""

  //list files in directory
  , listDir: false
  //enable client-side cache(304)
  , cache: true
  //enable debug information output
  , debug: true
  //enable cache of template/include file (when enabled templates will not be refreshed before restart)
  , templateCache: true

  //default pages, only one is supported
  , defaultPage: "index.html"
  //404 template/static file
  , 404:         "404.tmpl"
  //show errors to user(displayed in response)
  , showError: true

  Session timeout, in milliseconds.
  , sessionTimeout: 1440000

  //session file stored here
  , sessionDir: os.tmpDir()

  //session domain, e.g. ".google.com"
  , sessionDomain: ""

  //tempary upload file stored here
  , uploadDir:  os.tmpDir()

Extension on reponse object

Ouput file, filepath relative to the root

res.sendRootFile(filePath, [callback]);

Ouput file, filepath relative to the home (web dir)


Reidrect request


Return request object


Set Content-Type


Set/Remove Cookie

//Set Cookie
res.cookie(name, value [, {domain: string, path: string, expires: date, secure, httponly }])
//Remove Cookie
res.cookie(name, null);

Change default charset

res.charset = 'utf-8'

Mapping url to file, webSvr.url equal to webSvr.handle

webSvr.url("sitetest", ["svr/sitetest.js"]);

Mapping url to string

webSvr.url("hello", "Hello WebSvr!")

Handle post

webSvr.post("post.htm", function(req, res) {
    res.end('Received : ' + req.body);

//Equal to
webSvr.handle("post.htm", function(req, res) {
    res.end('Received : ' + req.body);
}, {post: true});

Post type

post: true/"json"/"qs"

Handle session

webSvr.session("session required url", function(req, res) {

Handle upload file, it's a specfic filter

webSvr.file("upload.do", function(req, res) {
  res.writeHead(200, {"Content-Type": "text/plain"});
  //Upload file is stored in req.files
  //form fields is stored in req.body

Valid File beofre receing it

* Valid request before receiving
webSvr.file("upload.do", function(req, res) {
  res.writeHead(200, {"Content-Type": "text/plain"});
}).before(function(req, res) {
  if ((req.headers['content-length'] || 0) > 245760) {
    res.send('Posting is too large, should less than 240K')
  } else {
    return true

Multi-Mapping in Handler or Filter

webSvr.handle(["about", "help", "welcome"], function(req, res) {
    res.writeFile(req.url + ".shtml");
}, {post: true});

Pickup parameters from url expression

webSvr.handle("/verify/:id", function(req, res) {
  var id = req.params.id;

Parse parameters in url

* expression = /home/:key/:pager
*   /home/JavaScript => { id: 'JavaScript', pager: '' }
*   /key/JavaScript  => false 

var params = webSvr.parseUrl(expression, reqUrl);

Send API

webSvr.send([type or statusCode, ] content);


webSvr.send('json', { a: 1, b: 2 });

Send String

webSvr.send(401, 'No permission');

Start a https server, make sure that the port will no conflict with others.

var httpsSvr = new WebSvr({
    home: "./"

  //disable http server
  , port:      null

  //enable https server
  , httpsPort: 8443
  , httpsKey:  require("fs").readFileSync("svr/cert/privatekey.pem")
  , httpsCert: require("fs").readFileSync("svr/cert/certificate.pem")


Do you want to re-use the filters & handlers?

httpsSvr.filters   = webSvr.filters;
httpsSvr.handlers  = webSvr.handlers;

Install: npm install websvr-redis

var RedisStore = require('websvr-redis');

    port: 6379
  , host: 'ourjs.org'
  , auth: 'your-password-if-needed'
  , select: 0

httpsSvr.sessionStore = RedisStore;

Clear expired sessions, only 1 refresh timer is needed

setInterval(RedisStore.clear, 1000000);

MIT, see our license file

  1. ourjs: url ourjs.com
  2. icalc: url icalc.cn, source code github


基于NodeJS的一个极简Web服务器, 专为ARM设计。 假设嵌入式设备需要保持长时间稳定运行,当遇到问题时也可自动重启并恢复此前用户的Session会话。