Лекция 09
// *nix
DEBUG=express:* node index.js
// Windows
set DEBUG=express:* & node index.js
// JS
process.env.DEBUG = 'express:*';
const logger = (req, res, next) => {
console.log(req.url);
next();
};
const hello = (req, res) => {
res.send('hello');
};
app.use(express.static('.'), { index: false });
app.use(logger);
app.use(hello);
express:router use / query +1ms
express:router use / expressInit +1ms
express:router use / serveStatic +1ms
express:router use / logger +0ms
express:router use / hello +0ms
GET http://127.0.0.1:3000/
express:router dispatching GET / +1s
express:router query : / +1ms
express:router expressInit : / +0ms
express:router serveStatic : / +1ms
express:router logger : / +3ms
express:router hello : / +0ms
const options = {
caseSensitive: false,
strict: false,
mergeParams: false
};
// caseSensitive: false
'/news' === '/News'
// strict: false
'/news' === '/news/'
// mergeParams: false
const news = express.Router();
const comments = express.Router();
comments.get('/:commentId', (req, res) => {
console.log(req.params);
res.send(`c#${req.params.commentId}
/ n#${req.params.newsId}`);
});
news.use('/:newsId/comments', comments);
app.use('/news', news);
// mergeParams: false
GET http://127.0.0.1:3000/news/1/comments/2
{ commentId: '2' }
c#2 / n#undefined
// mergeParams: true
const news = express.Router();
const comments
= express.Router({ mergeParams: true });
comments.get('/:commentId', (req, res) => {
console.log(req.params);
res.send(`c#${req.params.commentId}
/ n#${req.params.newsId}`);
});
news.use('/:newsId/comments', comments);
app.use('/news', news);
// mergeParams: true
GET http://127.0.0.1:3000/news/1/comments/2
{ newsId: '1', commentId: '2' }
c#2 / n#1
// mergeParams: true
const news = express.Router();
const comments
= express.Router({ mergeParams: true });
comments.get('/:id', (req, res) => {
console.log(req.params);
res.send(`c#${req.params.id}`);
});
news.use('/:id/comments', comments);
app.use('/news', news);
// mergeParams: true
GET http://127.0.0.1:3000/news/1/comments/2
{ id: '2' }
c#2
const app = express();
app.locals.title = 'My App';
app.locals.email = 'me@myapp.com';
...
const logger = (req, res, next) => {
console.log(req.app.locals.title);
next();
};
const app = express(); // the main app
const admin = express(); // the sub app
admin.get('/', (req, res) => {
console.log(admin.mountpath); // /admin
res.send('Admin Homepage');
});
app.use('/admin', admin); // mount the sub app
const app = express(),
blog = express(),
blogAdmin = express();
app.use('/blog', blog);
blog.use('/admin', blogAdmin);
console.log(app.path()); // ''
console.log(blog.path()); // '/blog'
console.log(blogAdmin.path()); // '/blog/admin'
app.param('userId', (req, res, next, id) => {
User.find(id, (err, user) => {
if (err) next(err);
req.user = user;
next();
});
});
app.get('/user/:userId', (req, res) => {
...
});
app.get('/user/:userId/comment', (req, res) => {
...
});
app.param('id', (req, res, next, id) => {
console.log('CALLED ONLY ONCE');
next();
});
app.get('/user/:id', (req, res, next) => {
console.log('although this matches');
next();
});
app.get('/user/:id', (req, res) => {
console.log('and this matches too');
res.end();
});
GET http://127.0.0.1:3000/user/42
CALLED ONLY ONCE
although this matches
and this matches too
app.param(['id', 'page'], function (req, res, next, value) {
console.log('CALLED ONLY ONCE with', value);
next();
});
app.get('/user/:id/:page', function (req, res, next) {
console.log('although this matches');
next();
});
app.get('/user/:id/:page', function (req, res) {
console.log('and this matches too');
res.end();
});
CALLED ONLY ONCE with 42
CALLED ONLY ONCE with 3
although this matches
and this matches too
app.get(property);
app.set(property, value);
app.disable(property);
app.enable(property);
app.disabled(property);
app.enabled(property);
case sensitive routing // '/Foo', '/foo'
etag
strict routing // '/foo', '/foo/'
query parser | Varied
false
'simple' - querystring
'extended' - qs
function
// https://www.npmjs.com/package/qs
'foo[bar][baz]=foobarbaz'
=>
{
foo: {
bar: {
baz: 'foobarbaz'
}
}
}
// https://www.npmjs.com/package/qs
'a[]=b&a[]=c'
=>
{
a: ['b', 'c']
}
// https://www.npmjs.com/package/qs
'a[0]=b&a[2]=c&a[1]=d'
=>
{
a: ['b', 'd', 'c']
}
env | String
'production'
'development'
x-powered-by | Boolean
"X-Powered-By: Express" HTTP header
app.set('title', 'Brand New App');
app.get('title');
> 'Brand New App'
app.get('/news', (req, res) => { ... });
GET http://127.0.0.1:3000/news/42/comments?sort=desc
req.baseUrl
> '/news' // маршрут сработавшего middleware
req.path
> '/42/comments'
req.originalUrl
> '/news/42/comments'
app.get('/news', (req, res) => { ... });
GET http://example.com/news/42/comments?sort=desc
req.hostname
> 'example.com'
req.ip
> '127.0.0.1'
req.protocol
> 'http'
req.fresh
req.stale
// cache-control, etag
// if-modified-since, if-none-match
app.use((req, res, next) => {
if (req.method === 'PUT') {
res.status(405)
.send('Invalid method');
}
else {
next();
}
});
app.get('/news/:id', (req, res, next) => { ... });
GET 127.0.0.1:3000/news/42
req.params
> { id: 42 }
app.get('/news/*/*', (req, res, next) => { ... });
GET 127.0.0.1:3000/news/42/comment
req.params
> { '0': '42', '1': 'comment' }
req.params[0]
> '42'
GET /search?q=tobi+ferret
req.query.q
> 'tobi ferret'
GET /shoes?order=desc&shoe[color]=blue
&shoe[type]=converse
req.query.order
> 'desc'
req.query.shoe.color
> 'blue'
req.query.shoe.type
> 'converse'
GET https://example.com/news
req.secure
> true
req.protocol == 'https'
GET tobi.ferrets.example.com
req.subdomains
> ["ferrets", "tobi"]
POST example.com
req.xhr
> true
// XMLHttpRequest
// Accept: text/*, application/json
req.accepts('html');
> 'html'
req.accepts('text/html');
> 'text/html'
req.accepts(['json', 'text']);
> 'json'
req.accepts(['text', 'json']);
> 'json'
req.accepts('image/png');
req.accepts('png');
> undefined
req.acceptsCharsets(charset [, ...]);
req.acceptsEncodings(encoding [, ...]);
req.acceptsLanguages(lang [, ...]);
req.header('Content-Type');
> "text/plain"
req.header('content-type');
> "text/plain"
req.get('Content-Type');
> "text/plain"
// With Content-Type: text/html; charset=utf-8
req.is('html');
req.is('text/html');
req.is('text/*');
> true
// When Content-Type is application/json
req.is('json');
req.is('application/json');
req.is('application/*');
> true
req.is('html');
> false
res.append('Set-Cookie', 'foo=bar;');
res.append('Warning', '199 warnings');
res.cookie('name', 'tobi',
{
domain: '.example.com',
path: '/admin',
secure: true,
maxAge: 900000
});
res.cookie('rememberme', '1',
{
expires: new Date(Date.now() + 900000),
httpOnly: true
});
res.clearCookie('__auth_id');
res.format({
'text/plain': () => {
res.send('hey');
},
'text/html': () => {
res.send('hey
');
},
'application/json': () => {
res.send({ message: 'hey' });
},
'default': () => {
res.status(406).send('Not Acceptable');
}
});
res.format({
text: function(){
res.send('hey');
},
html: function(){
res.send('hey
');
},
json: function(){
res.send({ message: 'hey' });
}
});
res.json(null);
res.json({ user: 'tobi' });
res.status(500).json({ error: 'message' });
res.redirect('/foo/bar');
res.redirect('http://example.com');
res.redirect(301, 'http://example.com');
res.redirect('../login');
res.send(new Buffer('whoop'));
res.send({ some: 'json' });
res.send('some html
');
res.status(404)
.send('Sorry, we cannot find that!');
res.status(500)
.send({ error: 'something blew up' });
const options = {
root: __dirname + '/public/',
dotfiles: 'deny',
headers: {
'x-timestamp': Date.now(),
'x-sent': true
}
};
const errorHandler = (err) => { ... };
res.sendFile(fileName, options, errorHandler);
// res.status(200).send('OK')
res.sendStatus(200);
// res.status(403).send('Forbidden')
res.sendStatus(403);
// res.status(404).send('Not Found')
res.sendStatus(404);
// res.status(500).send('Internal Server Error')
res.sendStatus(500);
res.set('Content-Type', 'text/plain');
res.get('Content-Type');
res.set({
'Content-Type': 'text/plain',
'Content-Length': '123',
'ETag': '12345'
});
res.end();
res.status(404).end();
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser());
cookieParser(secret, options)
app.use(cookieParser('my private key'));
res.cookie('user', 'tobi', { signed: true });
Cookie: user=tobi.CP7AWaXDfAKIRfH49dQzKJx7sKzzSoPq7/AcBBRVwlI3
req.cookies.user
> user=tobi.CP7AWaXDfAKIRfH49dQzKJx7sKzzSoPq7/AcBBRVwlI3
req.signedCookies.user
> "tobi"
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
bodyParser.json(options)
inflate // прием сжатых данных, true
limit // макс. размер тела, '100kb'
reviver // ф-я трансформации выходного объекта
strict // только объекты и массивы, true
bodyParser.raw(options)
inflate
limit
bodyParser.text(options)
defaultCharset // кодировка, 'utf-8'
inflate
limit
bodyParser.urlencoded(options)
extended // querystring vs qs
inflate
limit
parameterLimit // макс. число параметров, 1000