Node JS
part 2
NPM
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "server.js",
"dependencies": {
"lodash": "^4.17.21"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "",
"license": "MIT"
}
version http://semver.org:
x.x.x
x.x.1 - path - фикс багов
x.1.x - minor - изменения добавляют новые возможности, но не ломает предыдущие
1.x.x - major - вносят правки которые требуют изменений от потребителей
NPM
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "server.js",
"dependencies": {
"lodash": "^4.17.21"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "",
"license": "MIT"
}
main - задает точку входа в пакет.
Module util
const util = require('util');
const str = util.format("My %s %d %j", "string", 123, {test: "obj"});
console.log(str);
console.log("My %s %d %j", "string", 123, {test: "obj"});
- %s - String.
- %d - Number (both integer and float).
- %j - JSON.
- %% - single percent sign ('%'). This does not consume an argument.
Наследование от ошибок
const phrase = {
hello: 'привет',
world: 'мир',
}
function getPhrase(key) {
if (!phrase[key]) {
throw new Error("Phrase absent"); // HTTP 500
}
return phrase[key];
}
function makePage(url) {
if (url !== 'index.html') {
throw new Error("Page absent"); // HTTP 404
}
return url;
}
console.log(makePage('index'))
console.log(getPhrase('index'))
Наследование от ошибок
class PhraseError extends Error {
constructor(message) {
super(message);
}
}
class HttpError extends Error {
constructor(status, message) {
super(message);
this.status = status;
}
}
const phrase = {
hello: 'привет',
world: 'мир',
}
function getPhrase(key) {
if (!phrase[key]) {
throw new PhraseError(
`Phrase absent ${key}`
); // HTTP 500
}
return phrase[key];
}
function makePage(url) {
if (url !== 'index.html') {
throw new HttpError(
404, "Page absent"
); // HTTP 404
}
return url;
}
try {
console.log(makePage('index'))
console.log(getPhrase('index'))
} catch (err) {
if (err instanceof HttpError) {
console.log(err.status, err.message);
} else {
console.log( err.message);
}
}
События EventEmiter
const EventEmitter = require('events').EventEmitter;
const emitter = new EventEmitter();
emitter.on('request', function(request) {
request.approved = true;
});
emitter.on('request', function(request) {
console.log(request);
});
emitter.emit('request', {from: 'user 1'});
emitter.emit('request', {from: 'user 2'});
События EventEmiter
server.emit('error')
server.emit('error', new Error('test'))
События EventEmiter
const EventEmitter = require('events').EventEmitter;
const db = new EventEmitter();
class RequestApi {
constructor() {
db.on('data', function () {
this.send({test: 'test'});
})
}
send(data) {
console.log(data);
}
}
const req1 = new RequestApi();
const req2 = new RequestApi();
Нужно отписываться от навешенных событий что бы не расходовалась память.
События EventEmiter
const EventEmitter = require('events').EventEmitter;
const db = new EventEmitter();
class RequestApi {
constructor() {
db.on('data', this.onData)
}
onData(info) {
this.send(info);
}
send(data) {
console.log(data);
}
end() {
db.removeListener('data', this.onData);
}
}
const req1 = new RequestApi();
req1.end();
const req2 = new RequestApi();
req2.end();
Реализуем отписку от событий
Web server
const http = require('http');
const server = new http.Server(); // EventEmitter
// Добавляем подписку
server.listen(1337, '127.0.0.1');
// слушаем событие
server.on('request', function (req, res) {
res.end('Hello');
});
При запуске ноды, нода один раз считывает файл и создает обьект модуля. При изминении в коде нужно перезапускать.
echo server
// http://127.0.0.1:1337/echo?message=Hello -> Hello
const http = require('http');
const server = new http.Server(function (req, res) {
console.log(req.method, req.url);
res.end(); // если не указать ответ, то браузер будет ждать ответа
});
// Добавляем подписку
server.listen(1337, '127.0.0.1');
echo server
// http://127.0.0.1:1337/echo?message=Hello -> Hello
const http = require('http');
const url = require('url');
const server = new http.Server(function (req, res) {
console.log(req.method, req.url);
const urlData = url.parse(req.url, true);
console.log(urlData);
res.end(urlData.query.message);
});
// Добавляем подписку
server.listen(1337, '127.0.0.1');
Теперь выведем из req параметров значение
echo server
// http://127.0.0.1:1337/echo?message=Hello -> Hello
const http = require('http');
const url = require('url');
const server = new http.Server(function (req, res) {
res.statusCode = 404; // status code
res.end();
});
// Добавляем подписку
server.listen(1337, '127.0.0.1');
Return error.
echo server
// http://127.0.0.1:1337/echo?message=Hello -> Hello
const http = require('http');
const url = require('url');
const server = new http.Server(function (req, res) {
console.log(req.headers); // headers
res.end();
});
// Добавляем подписку
server.listen(1337, '127.0.0.1');
headers
http
module fs
const fs = require('fs');
fs.readFile(__filename, (err, data) => {
if (err) {
console.error(err)
return
}
console.log(data)
});
const fs = require('fs');
fs.readFile(__filename, (err, data) => {
if (err) {
console.error(err)
return
}
console.log(data.toString())
});
const fs = require('fs');
fs.readFile(__filename, 'utf-8', (err, data) => {
...
});
module fs
Что бы проверить наличие файла fs.stat(path[, options], callback)
module fs and path
Что бы проверить наличие файла используем path.
npm i mime
// http://localhost:3000/index.html?secret=true
const http = require('http');
const fs = require('fs');
const url = require('url');
const path = require('path');
const mime = require('mime');
const ROOT = __dirname + "/public/";
http.createServer(function(req, res) {
if (!checkAccess(req)) {
res.statusCode = 403;
res.end("Tell me the secret to access!");
return;
}
sendFileSafe(url.parse(req.url).pathname, res);
}).listen(3000);
function checkAccess(req) {
return url.parse(req.url, true).query.secret === 'true';
}
function sendFileSafe(filePath, res) {
try {
filePath = decodeURIComponent(filePath); // декодируем %D1%8F
} catch(e) {
res.statusCode = 400;
res.end("Bad Request");
return;
}
// Убираем лишние . и /
filePath = path.normalize(path.join(ROOT, filePath));
// Проверям что путь начинается с рута
if (filePath.indexOf(ROOT) != 0) {
res.statusCode = 404;
res.end("File not found");
return;
}
fs.stat(filePath, function(err, stats) {
if (err || !stats.isFile()) {
res.statusCode = 404;
res.end("File not found");
return;
}
sendFile(filePath, res);
});
}
function sendFile(filePath, res) {
fs.readFile(filePath, function(err, content) {
if (err) throw err;
const mimeType = mime.getType(filePath);
res.setHeader('Content-Type', mimeType + "; charset=utf-8"); // text/html image/jpeg
res.end(content);
});
}
express
Ставим глобально
npm install express-generator -g
что бы использовать генератор.
express --helper
express
Создаем приложение
express
Подключение движка рендера ejs
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// view engine setup
app.engine('ejs', require('ejs-locals')); // layout partial block
app.set('views', __dirname + '/template');
app.set('view engine', 'ejs');
или ejs-local
нужно установить npm i ejs-locals
express
Обработчики в express называются миделварами.
app.use(function(req, res, next) {
res.end('');
});
next случжит для того что бы передать управление дальше.
app.use(function(req, res, next) {
if (req.url == '/test') {
res.end("Test");
} else {
next();
}
});
app.use(function(req, res, next) {
if (req.url == '/') {
res.end("Hello");
} else {
next();
}
});
express
Свой обработчик ошибок
app.use(function(req, res, next) {
if (req.url == '/forbidden') {
next(new Error("wops, denied"));
} else {
next();
}
});
app.use(function(err, req, res, next) {
// NODE_ENV = 'production'
if (app.get('env') == 'development') {
var errorHandler = express.errorHandler();
errorHandler(err, req, res, next);
} else {
res.send(500);
}
});
NodeJS part2
By Oleg Rovenskyi
NodeJS part2
NodeJS part2
- 230