No description, website, or topics provided.
JavaScript HTML Shell
Switch branches/tags
Nothing to show
Latest commit bb1af30 Dec 11, 2015 @newghost update version
Permalink
Failed to load latest commit information.
website Add 'before' validation before receiving posting data Jan 18, 2015
websvr update Nov 13, 2015
.gitignore Start server by default Aug 15, 2014
LICENSE Add LICENSE file Sep 1, 2013
README.md update README.md Jul 29, 2015
package.json update version Dec 11, 2015

README.md

WebSvr

A simple web server, implement with filter and handler.

Features

  • 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

Install

npm install websvr

Start

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

Filter (HttpModule)

Session based authentication, basically useage:

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


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

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
    req.filter.next();
  } else {
    req.filter.next();
  }
}, { session: true });

Handler (HttpHandler, Servlet)

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;
  console.log(qs);
  if (qs.username == "admin" && qs.password == "12345678") {
    //Add username in session
    var session = req.session.set("username", qs.username);
    console.log(session);
    res.redirect("setting.htm");
  } else {
    res.writeHead(401);
    res.end("Wrong username/password");
  }
}, 'qs');

Note:

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)

etc:

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.

Cookies

//get cookie value by key
req.cookies[key];

Template

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,

webSvr.engine(engineFunc);

for example:

webSvr.engine(require("doT").compile);
webSvr.engine(require("jade").compile);

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.

webSvr.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 = {};
webSvr.model(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;
  console.log(model);
});

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.###

<body>
<!--#include="header.part"-->
<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

webSvr.clear()

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.

Settings

Return configuration of current WebSvr instance

webSvr.settings

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

Response

Extension on reponse object

Ouput file, filepath relative to the root

res.sendRootFile(filePath, [callback]);

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

res.sendFile(filePath);
res.sendHomeFile(filePath);

Reidrect request

res.redirect(url);

Return request object

res.req

Set Content-Type

res.type('xml');

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'

WebSvr APIs

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) {
    console.log(req.session);
    res.end();
});

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
  res.write(JSON.stringify(req.body));
  res.end(JSON.stringify(req.files));
});

Valid File beofre receing it

/*
* Valid request before receiving
*/
webSvr.file("upload.do", function(req, res) {
  res.writeHead(200, {"Content-Type": "text/plain"});
  res.send(req.files);
}).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);

Send JSON

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

Send String

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

Multi-instance support

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

}).start();

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

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

Store session in redis

Install: npm install websvr-redis

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

RedisStore.start({ 
    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);

Lincenses

MIT, see our license file

Demo Sites

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

Websvr

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