Nestia Web Component
{
common: {
expressApp: null,
listenHostname: '',
listenPort: 3000,
},
cache: {
impl: 'memory',
},
log: {
path: '',
level: '',
extraZipStreams: [],
takeOverConsole: false,
extraOutputStreams: {
info: process.stdout,
error: process.stderr,
},
},
ajax: {
timeout: 10000,
slowThreshold: 3000,
defaultHeaders: {
"X-Requested-With": "Nestia Web component V2.0"
},
agentOptions:{}
},
manifest: {
path: '',
name: '',
},
config: {
server: '',
},
monitor: {
prefix: '',
suffix: '',
mem: true,
cpu: true,
req404: true,
req5xx: true,
},
isPrimaryProcess: cluster.isPrimary || cluster.isMaster
}
- common.expressApp (object) optional,Express.app object.
- common.listenHostname (string) optional, hostname or ip http server listens on, used for config server callback.
- common.listenPort (number) optional,port number http server listens on, used for config server callback.
- cache.impl (string) optional, cache implementation, default is memory.
- log.path (string) optional, directory to save log files.
- log.level (string) optional, minimal level written to log file,default is info.
- log.extraZipStreams (array) optional, streams for access log.
- log.takeOverConsole (bool) optional, default false, indicate log module take over system console, thus all console message will be pipe to log file.
- log.extraOutputStreams (Object) optional, default null, extra log output stream, should be {info:[...Writable],error:[...Writable]}.
- ajax.timeout (number) optional, default timeout in millisecond, default is 10000.
- ajax.slowThreshold (number) optional, default slow log time limit in millisecond, all backend response time greater than limit will be logged to slow log file, default value is 50.
- ajax.defaultHeaders (object) optional, default headers send to backend, default value is {'x-requested-with':'Nestia Web Server 1.0'}.
- ajax.agentOptions (object) optional, extra agent options will pass to http/https agent, also will applied to globalAgent.
- manifest.path (string) optional, directory contain manifest file.
- manifest.name (string) optional, manifest name to load.
- config.server (string) optional, configuration server .
- config.hostPath (string) optional, configuration server .
- monitor.prefix (string) optional, prefix of all monitor keys.
- monitor.suffix (string) optional, suffix of all monitor keys.
- monitor.mem (bool) optional, auto monitor memory usage, default is false.
- monitor.cpu (bool) optional, auto monitor cpu usage, default is false.
- monitor.req404 (bool) optional, monitor 404 requests, default is false.
- monitor.req5xx (bool) optional, monitor 5xx requests, default is false.
- isPrimaryProcess (bool) optional, indicate current process is primary in cluster mode, monitor module will act differently when run as a worker process.
@deprecated
var NestiaWeb = require('nestia-web'); //this line must @ top ,before any routes or app filters. app.use(NestiaWeb.requestFilter());
.....
var Monitor = NestiaWeb.monitor; Monitor.init(configObj);
{ app: Express.app object (obj,required) prefix: monitor default prefix (string,optional) suffix: monitor default suffix (string,optional) mem: monitor memory usage (boolean,optional) cpu: monitor cpu usage (boolean,optional) mon404: monitor 404 response (boolean,optional) mon5xx: monitor 5xx response (boolean,optional) monitorPath: the path for express which remove graph drawer used to get monitor indicators and values }
- Used to adept nestia ip rule,when using request.ip property.
- add req.realUrl property presents the url send to nginx.
Provides function to resolve request headers,such as accept-language or user-agent.
param:
- req: express request object
return:
{
isBot: false,
isNestiaServer: false,
isNestiaClient: true,
isNestiaBusClient: false,
isNestiaAppClient: false,
isNestiaLotteryClient: false,
isNestiaMalaysiaLotteryClient: false,
isNestiaAgentClient: true,
nestiaClientId: "b23b2e8cc2bb3e38" / "60D42196-426C-4717-91B1-A7A72FE48AF9", #exists only when isNestiaClient === true or isNestiaAgentClient === true
isWinPhone: false,
isIPhone: false,
isIPad: false,
isAndroid: false,
isOtherMobile: false,
isMobile: false,
isWechatMiniProg: false,
platform: "windows" | "ios" | "android" | "linux" | "macos" | "whatsapp" | "compatible" | "unknown",
platformVersion: "10.3.1",
browser: "msie" | "opera" | "firefox" | "chrome" | "facebook" | "weixin" | "safari" | "unknown",
browserVersion: "10.3.1"
}
param:
- req: express request object
- is4PC: true means client is requesting a web page for PC not mobile device.
return:
{
languages: {
"zh-CN": "0,8",
"en": "0,6"
},
primaryLanguage: ["zh-CN"],
isEnglish: false,
lang: "zh-cn" | "en"
}
- provide an logger by using getLogger
- automatically zip logs
- automatically removes oldlogs
- Requires init
- NestiaWeb.logger's method can be called at any time, but it won't output any data until init finished.
init options:
{
dir:path.join(__dirname,'/../logs'),
streams:FileStreamRotator.getStream({...}) | [FileStreamRotator.getStream({...})]
}
Usage Example:
NestiaWeb.logger.info('some text',someObject);
let NestiaWeb=require('nestia-web');
let manifest=NestiaWeb.manifest;
let value=manifest.get('prop1.prop2.prop3');
......
Ajax API
demo:
{
server:'lottery',
version:'v5.0'
path:'/toto/broadcast'
data:{
key1:1234,
key2:5678
},
method:'POST',
timeout:800,
reqContentType:'form',
resContentType:'json',
headers:{
SomeUserDefinedHeader:'this will pass to server'
},
isWeb:true,
anonymous:true,
cname:'toto_broadcast',
passClientIP:false,
req:req,
res:res
}
- server: (string) (required) Server code defined in manifest.
- version: (string) (optional) Version to replace '${version}' part in url.
- path: (string) (required) Api path apart from url defined in manifest.
- data: (object) (optional) Data will send to server.It should be a simple object.
- method: (string) (optional) Http method,default is 'GET'.
- timeout: (number) (optional) Timeout (microseconds) before server complete response,default is defined in config or init option DEFAULT_TIMEOUT.
- reqContentType (deprecated alias dataType): (string) (optional) request data format,only support 'json' and 'form'(default).
- resContentType (deprecated alias contentType): (string) (optional) Content format.If contentType set 'json' or server response with header 'content-type:application/json', response body will be decode automatically.
- headers: (object) (optional) Headers passed to server.Note:if req object is set,most of req.headers' property will passed to backend,no need to redefine headers in this option.
- isWeb: (bool) (optional) If true, and exists cookie named 'N1',then cookie N1's value will replace default Accept-Language value.Default is false.
- anonymous: (bool) (optional) If false, and exists cookie named 'token',then a header named 'Authorization' will be set with value of cookie 'token'.
- noCache: (bool) (optional) If true, headers named 'If-Modified-Since','If-None-Match' will be removed from header ,and 'Cache-Control' will be set 'no-cache'. Default is true.
- passClientIP: (bool) (optional) If true, headers ('X-Forwarded-For','X-Real-IP') will be passed to server. Default is true.
- req: (obj) (optional) (*required by proxy) By default,most of headers in req will pass to backend request.In proxy method,request's body stream will piped to backend request.
- res: (obj) (unnecessary)(*required by proxy) Proxy will handle response,when reject happened.Only if ret.status === 0 ,proxy don't handle response,you should end response, such as res.status(500).end() .
{
ok: false,
status: 0,
message: '',
error: null,
data: {},
raw: null,
headers: null,
totalCount: null,
duration: [0, 123000]
}
- ok: (bool) indicates request is successful.
- status: (number) http response code from backend server.
- message: (string) error message when exception or error happened.
- error: (Error) Error object,if exists.
- data: (*) parsed server response content.Object if content-type option set "json",string if content-type set something else.
- raw: (string) original server response text,null when calling proxy method.
- headers: (object) response headers.
- duration (array) [seconds,nanoseconds], time used from request start to finish.
- totalCount: (number) same value of response's headers["X-Total-Count"],null if header not exists.
NestiaWeb.ajax.request({
server: 'property',
version: 'v4.6',
timeout: 3000,
path: path,
method: 'POST',
isWeb:true,
req: req,
performance: false,
proxy: 'http://someuser:password@127.0.0.1:7666',
headers: {
'origin': 'https://property-staging.nestia.com'
}
}).then((data) => {
res.render('somepage',data.data);
}, (err) => {
req.app.locals.logger.error('error request backend API:' + err.message, err);
if (err.status) {
res.status(err.status).end();
}else{
res.status(500).end();
}
});
NestiaWeb.ajax.proxy({
server: 'property',
path: path,
method: 'POST',
isWeb:true,
req: req,
res: res,
headers: {
'origin': 'https://property-staging.nestia.com'
}
}).then((data) => {
}, (err) => {
NestiaWeb.logger.error('error upload property image:' + err.message, err);
if (!err.status) {
res.status(500).end();
}
});
- This method is a little like Promise.all
- When one of requests fails,you will always get a resolve callback, which is different from Promise.all.
- You can use data[n].ok to check whether request fails, and also you can get status, and raw data if exists.
NestiaWeb.ajax.request([
{
server: 'property',
version: 'v4.6',
timeout: 3000,
path: '/nearby'
},
{
server: 'news',
version: 'v4.8',
path: '/news'
}
]).then((datas) => {
let propertyData=datas[0];
let newsData=datas[1];
//assume property backend never fails.
if(!newsData.ok){
//news api fails
res.render('onlyProperty',propertyData.data);
}else{
res.render('fullContent',{property:propertyData.data,news:newsData.data});
}
});
let NestiaWeb=require('nestia-web');
let cache=NestiaWeb.cache;
//set a cache
//timeout is numeric presents seconds,default value is 300 seconds.
//when timeout is negitave number, the cache record will never expire.
cache.set('propName','propValue',30);
//get value
cache.get('propName').then(function(val){
//val should equal 'propValue'
});
//memory cache cleanup has 60 seconds deviation
setTimeout(function(){
cache.get('propName').then(function(val){
//val should be null
});
},30+60000);
cache.set('anotherPropName','anotherPropValue',30).then(()=>{
cache.set('anotherPropName',null,30);
});
//current memory cache implements synchronously.
cache.get('anotherPropName').then(function(val){
//val should be null
});
An easy way to access nestia config api.
parameters:
- configName: (required) Config file's name.
- contentType: (optional) See AJAX.requestOptions.contentType.
- useCache: (optional) Use local memory cache, default is true.
demo:
nestiaWeb.config.getConfig(
'app_config_' + ('' + req.params['version']).replace('.', '_') + '.json',
'json',
false
).then(function (result) {
try {
var result = JSON.parse(result.content);
// var lang = (/zh-cn|zh-han[st]-/.test((req.headers['accept-language'] || '').toLowerCase())) ? 'cn' : 'en';
var platform = /(IOS|iPhone)/.test(req.headers['user-agent']) ? 'ios' : 'adr';
res.setHeader('Content-Type', 'application/json;charset=UTF-8');
res.send(JSON.stringify(result[platform]));
} catch (e) {
res.setHeader('Content-Type', 'text/plain');
res.set('X-Error', 500);
res.status(500);
res.send(e.message + "<br/>\r\nOriginal content:" + result.data.content);
}
}, function (err) {
"use strict";
res.setHeader('Content-Type', 'text/plain');
res.set('X-Error', err.status);
res.status(500);
res.send('Error:' + err.status)
});
parameters:
- configName: (required) Config file's name.
- content: (required) Config value content. If content is plain object, it will be stringified to json string.If not, it will be converted to string.
demo:
nestiaWeb.config.setConfig(
'wechat_config',
{content:'this is a way to access wechat api'}
).then(function (result) {
try {
var result = JSON.parse(result.content);
//result is object {content:'this is a way to access wechat api'}
} catch (e) {
res.setHeader('Content-Type', 'text/plain');
res.set('X-Error', 500);
res.status(500);
res.send(e.message + "<br/>\r\nOriginal content:" + result.data.content);
}
}, function (err) {
"use strict";
res.setHeader('Content-Type', 'text/plain');
res.set('X-Error', err.status);
res.status(500);
res.send('Error:' + err.status)
});