"allow":允许带有点的文件
"deny":对请求点的文件发送一个403,同时调用下面一个中间件strict(默认为false):开启严格的路由。默认情况下/foo和/foo/是一致的
注意:可以添加中间件和HTTP方法的路由,如通过put/get/post等路由 var express = require('express');
var app = express();
app.get('/', function(req, res){
res.send('hello world');
});
app.listen(3000);
app对象有一下的方法:
.添加中间件,如app.route。用这种方式可以防止重名路由
var app = express();
app.route('/events')
.all(function(req, res, next) {
// runs for all HTTP verbs first
// think of it as route specific middleware!
})
.get(function(req, res, next) {
res.json(...);
})
.post(function(req, res, next) {
// maybe add a new event...
});
.渲染HTML视图,如app.render
// send the rendered view to the client
res.render('index');
// if a callback is specified, the rendered HTML string has to be sent explicitly
res.render('index', function(err, html) {
res.send(html);
});
// pass a local variable to the view
res.render('user', { name: 'Tobi' }, function(err, html) {
// ...
});
.添加一个模板引擎,如app.engine
var engines = require('consolidate');
app.engine('haml', engines.haml);
app.engine('html', engines.hogan);
.有一些配置信息会影响express应用的行为
app.locals:保存这个应用中的局部变量
app.locals.title
// => 'My App'
app.locals.email
// => '[email protected]'
只要设置了app.locals属性,那么在整个应用的生命周期内都是存在的。而res.locals属性仅仅在一个请求的生命周期中有效。你可以访问整个应用的访问模版中的局部变量。这对于为模板添加帮助函数非常有用,同时也可以提供一些应用层面的数据。局部的变量在中间件中可以通过req.app.locals来访问
app.locals.title = 'My App';
app.locals.strftime = require('strftime');
app.locals.email = '[email protected]';
app.mountpath:保存的是一个或者多个路由模式,在这个路由模式下我们可以添加一个一个子应用。子应用表示的是一个express实例,这个实例用于处理特定路由的请求。
var express = require('express');
var app = express(); //主应用
var admin = express(); //子应用
admin.get('/', function (req, res) { //子应用的真实的处理逻辑
console.log(admin.mountpath); // /admin就是moutpath
res.send('Admin Homepage');
});
app.use('/admin', admin); //添加子应用
mountpath和req对象的baseUrl相似,只是req.baseUrl返回的是一个URL,而不是匹配的模式。如果一个子应用被添加在多个路径模式下那么app.mountpath返回这个pattern的集合
var admin = express();
admin.get('/', function (req, res) {
console.log(admin.mountpath); // [ '/adm*n', '/manager' ]
res.send('Admin Homepage');
});
var secret = express();
secret.get('/', function (req, res) {
console.log(secret.mountpath); // /secr*t
res.send('Admin Secret');
});
admin.use('/secr*t', secret); // load the 'secret' router on '/secr*t', on the 'admin' sub app
app.use(['/adm*n', '/manager'], admin); // load the 'admin' router on '/adm*n' and '/manager', on the parent app
我们看到admin是被绑定到['/adm*n','/manager']上面的,所以对于admin来说其mountpath就是这个数组。而对于secret来说,其通过admin来使用的额,而admin使用的时候被绑定到"/secr*t"路径上。
很显然看到这里对于secret来说其mountpath不是/manager/secr*t!
var admin = express();
admin.on('mount', function (parent) {
console.log('Admin Mounted');
console.log(parent); // refers to the parent app
});
admin.get('/', function (req, res) {
res.send('Admin Homepage');
});
app.use('/admin', admin);
注意:子应用不会继承值为默认值的配置信息,你必须自己在子应用上面的手动设置。同时他会自动继承不是默认值的配置信息
方法篇:
app.all(path, callback [, callback ...])
这个方法会拦截所有的HTTP动词的请求。如果把下面这个路由添加在其他路由的前面,这时候所有的去请求必须授权,同时他会自动查询一个用户。而且这时候loadUser还可以通过调用next来继续执行后面的二路由
app.all('*', requireAuthentication, loadUser);
这个方法和下面是完全一致的:
app.all('*', requireAuthentication)
app.all('*', loadUser);
下面可以实现全局的白名单功能。但是路径必须是"/api"开始的
app.all('/api/*', requireAuthentication);
app.delete(path, callback [, callback ...])
app.delete('/', function (req, res) {
res.send('DELETE request to homepage');
});
app.disable(name)
就是把name设置为false,name的属性的值可以参考app的setting表格。如通过app.set('foo',false)相当于调用app.disable('foo')。
app.disable('trust proxy');
app.get('trust proxy');
// => false
app.disabled(name)
app.disabled('trust proxy');
// => true
app.enable('trust proxy');
app.disabled('trust proxy');
// => false
app.enable(name)
app.enable('trust proxy');
app.get('trust proxy');
// => true
app.engine(ext, callback)
app.engine('jade', require('jade').__express);
如果为没有提供.__express的引擎使用这个方法,或者你想要为引擎指定一个不同的后缀。如下面的例子
app.engine('html', require('ejs').renderFile);
这时候,EJS提供了一个renderFile方法,这个方法的签名和Express期望的是一样的:(path,options,callback)。这个方法还有一个内部相同功能的函数,也就是ejs._express,因此如果你使用.ejs后缀那么不需要做任何处理。
var engines = require('consolidate');
app.engine('haml', engines.haml);
app.engine('html', engines.hogan);
app.get(name)
app.get('title');
// => undefined
app.set('title', 'My Site');
app.get('title');
// => "My Site"
app.get(path, callback [, callback ...])
app.get('/', function (req, res) {
res.send('GET request to homepage');
});
app.listen(port, [hostname], [backlog], [callback])
var express = require('express');
var app = express();
app.listen(3000);
返回的app其实是一个javascript的函数,这个函数被传入到Node的HTTP服务器作为一个请求的回调函数。这样你就可以为为你的应用同时添加HTTP和HTTPS版本的处理函数
var express = require('express');
var https = require('https');
var http = require('http');
var app = express();
http.createServer(app).listen(80);
https.createServer(options, app).listen(443);
我们知道app.listen方法返回一个http.Server对象,其实是后续代码的一个简化
app.listen = function() {
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
挂载中间件的方法:
app.use(function (req, res, next) {
next();
})
//一个router是有效的中间件。
var router = express.Router();
router.get('/', function (req, res, next) {
next();
})
app.use(router);
//一个Express程序是一个有效的中间件。
var subApp = express();
subApp.get('/', function (req, res, next) {
next();
})
app.use(subApp);
挂载一系列中间件:
var r1 = express.Router();
r1.get('/', function (req, res, next) {
next();
})
var r2 = express.Router();
r2.get('/', function (req, res, next) {
next();
})
app.use(r1, r2);
挂载一组中间件:
var r1 = express.Router();
r1.get('/', function (req, res, next) {
next();
})
var r2 = express.Router();
r2.get('/', function (req, res, next) {
next();
})
app.use('/', [r1, r2]);
在逻辑上使用一个数组来组织一组中间件。如果你传递一组中间件作为第一个或者唯一的参数,接着你需要指定挂载的路径。
function mw1(req, res, next) { next(); }
function mw2(req, res, next) { next(); }//第三种方式直接通过挂载函数来完成
var r1 = express.Router();//第一种方式通过express.Router来挂载
r1.get('/', function (req, res, next) { next(); });
var r2 = express.Router();
r2.get('/', function (req, res, next) { next(); });
var subApp = express();//第二种方式通过创建express实例来挂载中间件
subApp.get('/', function (req, res, next) { next(); });
app.use(mw1, [mw2, r1, r2], subApp);//组合多种方式挂载中间件
我们来仔细看看app具体的信息:
app.listen = function(){
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
这说明我们的app.listen方法实际上返回的是http.Server对象,那我们看看这个对象有什么具体的信息:
_events: { mount: [Function] },
_maxListeners: undefined,
setMaxListeners: [Function: setMaxListeners],
//因为app继承了http.Server,而http.Server继承了net.Server,而net.Server是一个EventEmitter实例
getMaxListeners: [Function: getMaxListeners],
//getMaxListeners函数
emit: [Function: emit],
//继承事件Class: EventEmitter
addListener: [Function: addListener],
//继承事件Class: EventEmitter
on: [Function: addListener],
//继承事件Class: EventEmitter
once: [Function: once],
//继承事件Class: EventEmitter
removeListener: [Function: removeListener],
//继承事件Class: EventEmitter
removeAllListeners: [Function: removeAllListeners],
//继承事件Class: EventEmitter,返回一个事件回调的数组
listeners: [Function: listeners],
//继承事件Class: EventEmitter
listenerCount: [Function: listenerCount],
这只是其中一部分关于事件的函数,仔细看看这个http.Server,我们发现他继承了net.Server,而net.Server又是EventEmitter实例,所以最后http.Server也就具有了EventEmitter所有的属性和方法。
request: IncomingMessage { app: [Circular] },
//request对象也是一个IncomingMessage对象,其中的app对象就是我们打印出来的整个对象
response: ServerResponse { app: [Circular] },
//response对象也是一个IncomingMessage对象,其中的app对象就是我们打印出来的整个对象
同时我们也可以看到app本身封装了两个IncomingMessage,其实他具有app所有的方法,其他一些配置信息 可以阅读
req对象的属性:
首先我们必须弄清楚一个问题:req对象是一个IncomingMessage对象,也就是下面打印true,IncomingMessage具有的所有属性这个req对象都是有的:httpVersionMajor,httpVersionMinor,httpVersion,headers,rawHeaders,trailers等。也有一些特定的属性:baseUrl,originalUrl,params,query,res,locals
var express=require('express');
var http=require('http');
var app=express();
function replacer(key, value) {
if (key === "car") {
return undefined;
}
return value;
}
app.set('json replacer', replacer);
app.set('json spaces',5)
app.set('x-powered-by',false);
//返回一个http.Server对象,然后继续调用其listen方法
var admin = express();
app.get('/',function(req,res){
console.log(req instanceof http.IncomingMessage);
});
req.app:中间件获取主页app对象
req.baseUrl(和app对象的mountpath属性相似,除了app.mountpath返回的是路径匹配模式
var express=require('express');
var app=express();
var admin = express();
//admin中间件的请求
admin.get('/', function (req, res) {
console.log(admin.mountpath); // [ '/adm*n', '/manager' ]
console.log(req.baseUrl); //返回的是/manager
res.send('Admin Homepage');
});
var secret = express();
secret.get('/', function (req, res) {
console.log(secret.mountpath); // /secr*t
console.log(req.baseUrl);
res.send('Admin Secret');
});
admin.use('/secr*t', secret); // load the 'secret' router on '/secr*t', on the 'admin' sub app
app.use(['/adm*n', '/manager'], admin); // load the 'admin' router on '/adm*n' and '/manager', on the parent app
app.listen(30000);
注意:如果这时候的访问路径为http://localhost:30000/manager/secret那么就会打印/secr*t和/manager/secret,所有说mountpath只是子引用挂载的路径,而req.baseUrl
返回的是实际的路径,其中的通配符全部转化为实际的路径了,而且是从app开始计算的路径,因为我们的listen是挂载在主应用app下!
// Host: "example.com"
req.hostname
// => "example.com"
一个布尔值,如果X-Requested-With的值为XMLHttpRequest,那么其为true,其指示这个请求是被一个客服端库发送,比如jQuery。
req对象的方法:
req.accepts(types)
检查这个指定的内容类型是否被接受,基于请求的Accept HTTP头部。这个方法返回最佳匹配,如果没有一个匹配,那么其返回undefined(在这个case下,服务器端应该返回 406和"Not Acceptable")。 ype值可以是一个单的MIME type字符串(比如application/json),一个扩展名比如json,一个逗号分隔的列表,或者一个数组。对于一个列表或者数 组,这个方法返回最佳项(如果有的话)。
req.acceptsCharsets(charset[, ...])
返回指定的字符集集合中第一个的配置的字符集,基于请求的Accept-CharsetHTTP头。如果指定的字符集没有匹配的,那么就返回false。
req.acceptsEncodings(encoding[, ...])
返回指定的编码集合中第一个的配置的编码,基于请求的Accept-EncodingHTTP头。如果指定的编码集没有匹配的,那么就返回false。
req.acceptsLanguages(lang [, ...])
返回指定的语言集合中第一个的配置的语言,基于请求的Accept-LanguageHTTP头。如果指定的语言集没有匹配的,那么就返回false。
req.get(field)
返回指定的请求HTTP头部的域内容(不区分大小写)。Referrer和Referer的域内容可互换。其是req.header(field)的别名。
req.get('Content-type');
// => "text/plain"
req.get('content-type');
// => "text/plain"
req.get('Something')
// => undefined
req.is(type)
// ?name=tobi
req.param('name')
// => "tobi"
// POST name=tobi
req.param('name')
// => "tobi"
// /user/tobi for /user/:name
req.param('name')
// => "tobi"
按下面给出的顺序查找:
res.app
这个属性持有express程序实例的一个引用,其可以在中间件中使用。 res.app和请求对象中的req.app属性是相同的。
res.headersSent
布尔类型的属性,指示这个响应是否已经发送HTTP头部。
res.locals:
包含的是某个请求中为response添加的局部变量,因此这个对象只对一个请求/响应生命周期中的视图可见。和app.locals类似。这个属性常用于暴露一些请求层面的信息,例 如请求路径名称,认证的用户,用户的设置等
app.use(function(req, res, next){
res.locals.user = req.user;
res.locals.authenticated = ! req.user.anonymous;
next();
});
resonse对象的方法:
res.append(field [, value])
res.append()方法在Expresxs4.11.0以上版本才支持。在指定的field的HTTP头部追加特殊的值value。如果这个头部没有被设置,那么将用value新建这个头部。value可以是一个字符串或者数组。 注意:在res.append()之后调用app.set()函数将重置前面设置的值。
res.append('Lind', ['', '']);
res.append('Set-Cookie', 'foo=bar;Path=/;HttpOnly');
res.append('Warning', '199 Miscellaneous warning');
res.attachment([filename])
res.attachment();
// Content-Disposition: attachment
res.attachment('path/to/logo.png');
// Content-Disposition: attachment; filename="logo.png"
// Content-Type: image/png
res.cookie(name, value [,options])
res.format({
'text/plain':function() {
res.send('hey')'
},
'text/html':function() {
res.send('hey
');
},
'application/json':function() {
res.send({message:'hey'});
},
'default':function() {
res.status(406).send('Not Acceptable');
}
除了规范化的MIME类型之外,你也可以使用拓展名来映射这些类型来避免冗长的实现:
res.format({
text:function() {
res.send('hey');
},
html:function() {
res.send('hey
');
},
json:function() {
res.send({message:'hey'});
}
})
res.get(field)
// ?callback=foo
res.jsonp({user:'tobo'})
// => foo({"user":"tobi"})
app.set('jsonp callback name', 'cb')
// ?cb=foo
res.status(500).jsonp({error:'message'})
// => foo({"error":"message"})
下面是三个例子:
方法1:通过jquery实现的jsonp请求:
function jsonp() {
//向服务器发送请求,回调函数由jquery自己指定
$.getJSON("http://127.0.0.1:30000/jsonp?callback=?",
function(data) {
alert(data.name);
});
}
对应的服务器代码为:
app.get('/jsonp',function(req,res,next){
//和res.json一样,不过jsonp可以触发回调函数
res.status(200).jsonp({name:'高山上的鱼'})
});
方法2:通过原生javascript实现的jsonp
function originalJsonp()
{
//回调函数
var url = "http://127.0.0.1:30000/jsonp1?pursue=callbackfunction";
var script = document.createElement('script');
script.setAttribute('src', url); //load javascript
document.getElementsByTagName('head')[0].appendChild(script);
}
function callbackfunction(data){
alert(data.name);
}
服务器端的代码为:
app.get('/jsonp1',function(req,res,next){
//console.log(req.query);
var callbackFunc=req.query.pursue;
var result=JSON.stringify({name:"qinliang"});
res.write(callbackFunc+"("+result+")");
res.end();
});
方法3:通过app.set('jsonp callback name', 'callbackfunction1') 自动修改回调函数
app.set('jsonp callback name', 'pursue')
app.get('/jsonp2',function(req,res,next){
//和res.json一样,不过jsonp可以触发回调函数
res.status(200).jsonp({name:'高山上的鱼'})
});
我们看看服务器返回的数据是什么:
/**/ typeof callbackfunction === 'function' && callbackfunction({"name":"高山上的鱼"});
res.links(links)
连接这些links,links是以传入参数的属性形式提供,连接之后的内容用来填充响应的Link HTTP头部(暂时不知道这个HTTP头有什么作用)。
var express=require('express');
var app = express()
app.get('/',function(req,res){
res.links({
next:'http://api.example.com/users?page=2',
last:'http://api.example.com/user?page=5'
});
res.end('高山上的鱼我爱你');
//打印Link:; rel="next", ; rel="last"
})
app.listen(10000, function() {
console.log('Ready');
});
res.location(path)
var express=require('express');
var app = express()
app.get('/',function(req,res){
//重定向到一个新的网址
res.status(301).location('http://www.baidu.com/');
res.end();
//也可以使用下面这种方式:
// res.setHeader('location','http://www.baidu.com');
// res.writeHead();//多次setHead只会在最后一次writeHead会发送HTTP头部
});
app.listen(9999, function() {
console.log('Ready');
});
当path参数为back时,其具有特殊的意义,其指定URL为请求对象的Referer头部指定的URL。如果请求中没有指定,那么其即为"/"。
// pass a local variable to the view
res.render('user', {name:'Tobi'}, function(err, html) {
// ...
});
res.send([body])
app.get('/file/:name', function(req, res, next) {
var options = {
root:__dirname + '/public',
dotfile:'deny',
headers:{
'x-timestamp':Date.now(),
'x-sent':true
}
};
var fileName = req.params.name;
res.sendFile(fileName, options, function(err) {
if (err) {
console.log(err);
res.status(err.status).end();
}
else {
console.log('sent', fileName);
}
});
});
res.sendStatus(statusCode)
res.sendStatus(200); // equivalent to res.status(200).send('OK');
res.sendStatus(403); // equivalent to res.status(403).send('Forbidden');
res.sendStatus(404); // equivalent to res.status(404).send('Not Found');
res.sendStatus(500); // equivalent to res.status(500).send('Internal Server Error')
//如果一个不支持的状态被指定,这个HTTP status依然被设置为statusCode并且用这个code的字符串作为Body。
res.sendStatus(2000); // equivalent to res.status(5000).send('2000');
res.set(field [, value])