02Dec

express_2_2

Favicon is the connect  of Middleware that checks whether the url has a view of favicon.ico; if the answer is ‘yes’, it reads favicon  and outputs, otherwise it transfers control further. The logger outputs a record what kind of a request we’ve received. For example, if we launch the app now, the logger will output something, when we follow:

http://localhost:3000/

That is a standard  Httplog requests, while dev is a logging format. There are also other formats – for example,  default (let us add the respective record in app.js):

app.use(express.favicon()); // /favicon.ico
if (app.get('env') == 'development') {
  app.use(express.logger('dev'));
} else {
  app.use(express.logger('default'));
}

Various formats can be found in the connect supporting materials. Here you will find different variants of built-in formats. There is one more amazing setting for adding a record into log. It often writes into log upon a request ending. But we can indicate immediate: true, and it will write into log in the very beginning.

But what is the difference, if we talk about our code? If we’ve got the option immediatea logger will write into logand further, through next, transfer control over the next  MiddlewareIt is the most likely control flow. But we’ve got a different thing by default – the logger rewrites res.end to its function that writes into log upon being called. So, it turns out, if we log this way, without the flag  immediatethen if log doesn’t contain anything, it doesn’t mean there was no request.

Keep that thing in mind. It may happen that the request really existed, but hung up because NODE didn’t handle it. Respectively, everything will go to log only upon the request end.

BodyParser deals with reading the forms sent via the post method, reads JSON data sent using this method. It means, the request body gets parsed. The data transferred through post, as well as similar methods get read using flows. This is an asynchronous action. BodyParser deals with all these things, absolutely reads post. And if it’s  JSON, itparse it, and the data becomes accessible in req.body:

app.use(express.bodyParser());  // req.body....

Once it has completely read the postthis Middleware transfers control further through next.

CookieParser parses as well, but cookies instead of the body. So, there may be headers like these: req.headers. It divides them and makes the respective properties of the object cookies:

app.use(express.cookieParser('your secret here')); // req.cookies

Here we can specify an optional key the cookies will be signed with. Right now we don’t need this record and will talk about it later.

Router allows us to talk seamlessly about what requests will be there and how they will be handled. For instance, let us add the following code:

app.use(app.router);

app.get('/', function(req, res, next) {
  res.end("Test")
});

Respectively, instead of get there may be post, putdel, etc. Moreover, this Middleware contains a number of extra options (you may transfer parameters, etc.).

The last Middleware is static. Generally, static gets displayed by other servers, not Node.js, but it can do it, too. So, if no Middleware handles the request here, the control gets delivered to Middleware static.

app.use(express.static(path.join(__dirname, 'public')));

It checks, whether the  public directory has got the respective file. Let us change the names of public directories a little bit(stylesheets-> css,  javascript->js). Launch it, everything works!

App.js looks like that, check it out:

var express = require('express');
var http = require('http');
var path = require('path');
var config = require('config');
var log = require('libs/log')(module);


var app = express();
app.set('views', __dirname + '/templates');
app.set('view engine', 'ejs');

app.use(express.favicon()); // /favicon.ico
if (app.get('env') == 'development') {
  app.use(express.logger('dev'));
} else {
  app.use(express.logger('default'));
}

app.use(express.bodyParser());
app.use(express.cookieParser());

app.use(app.router);

app.get('/', function(req, res, next) {
  res.end("Test")
});

app.use(express.static(path.join(__dirname, 'public')));

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

// var routes = require('./routes');
// var user = require('./routes/user');

// // all environments

// app.get('/', routes.index);
// app.get('/users', user.list);


http.createServer(app).listen(config.get('port'), function(){
  log.info('Express server listening on port ' + config.get('port'));
});

Eventually, instead of such a simple message, let us output a common HTML page. For that reason, I will create a new file in the template directory and call it index.ejs. The file extension is  ejssince a ejs-related template is usually created this way. The template itself is an HTML, and you can use special extra dividers in order to insert the code or variables, for example:

<!DOCTYPE html>
<html>
<head>
  <title>Hello, World!</title>
</head>
<body>
<section class="container">

  <h1>Hello, World!</h1>

  <%=body%>
  <%-body%>

</section>
</body>
</html>

We can find more detailed information in our technical materials. If we want some special example, the code may be:

<% if (user) { %> 
   <h2><%= user.name %></h2>   
<% } %> 

<% if (user) { means inserting the JavaScript code, which means the operator if will be executed, while %= means adding the variable values.  <%-body%> also means inserting of a variable. But if there is some kind of an unsafe text in the  body  (for example, <script>), in this case – <%-body%> – it will be inserted the way it is, and if there is <%=body%>, it will be changed with safe symbols.

Let us show the example of:

 <%=body%>
  <%-body%>

Of course, we need to transfer a variable to the template. But how can we do it?  The principle is very simple, just write in app.js:

app.get('/', function(req, res, next) {
  res.render("index", {
    body: '<b>Hello</b>'
  });
});

Check it. Enter

http://localhost:3000/

html

As you can see, the first body has been inserted marked with =, while the second – with -.

We’ve got the simplest Express website, with the output into the variable template. In our next article we will work a bit more with templates, front-end part, and then will move to the data.

The lesson code can be found here.
staytuned2

The materials for this article were borrowed from the following screencast.

We are looking forward to meeting you on our website soshace.com

19. Node.js Lessons. Safe Way to a FS File and Path

This article will deal with how to create a web server in Node.js, which will return a file to a user from a public directory. You may wonder: why do we need Node.js here? Why can’t we use another server? You question surely does make sense. Yes, for returning files other servers are generally more effective. From the other side, Node.js works pretty well, too. Second, before returning a file it can also perform some intellectual activities: for example, refer to a database, check out whether a user is permitted to access the file and give the file to him, if it’s permitted.

JAMstack Architecture with Next.js

The Jamstack architecture, a term coined by Mathias Biilmann, the co-founder of Netlify, encompasses a set of structural practices that rely on client-side JavaScript, reusable APIs, and prebuilt markup to build websites and applications. At its core, the Jamstack advocates for rendering web applications into static HTML files during the build process and serving them efficiently to clients.

Leave a Reply

02Dec

express_2_2

Favicon – это  все connect  Middleware, он смотрит, если url имеет вид favicon.ico, то он читает favicon  и выдает, а иначе передает управления дальше. Логгер выводит запись о том, что у нас за запрос пришел. Например, если сейчас запустить приложение, то логгер что-то выведет, если мы зайдем на:

http://localhost:3000/

То есть, это обычный  Http log запросов, dev – это формат логирования. Есть и другие форматы, например,  default. (сделаем такую запись в app.js):

app.use(express.favicon()); // /favicon.ico
if (app.get('env') == 'development') {
  app.use(express.logger('dev'));
} else {
  app.use(express.logger('default'));
}

Различные форматы можно посмотреть в документации connect. Здесь есть различные варианты встроенных форматов. Есть еще одна забавная настройка, когда писать в log. Обычно он пишет в log по окончанию запроса. Но можно указать immediate: true, и он будет писать log в самом начале.

Какая разница, если говорить о нашем коде? Если будет установлена опция immediate, тогда логгер будет писать в log, а потом через next передавать управление следующим Middleware. Это самый очевидный поток управления. Но по умолчанию происходит несколько другая вещь – логгер перезаписывает res.end на свою функцию, которая при вызове пишет в log. Из-за этого выходит, что если мы логируем таким способом, без флага immediate, то если в log ничего нет – это совсем не значит, что запроса не было.

Стоит иметь это в виду. Возможно, запрос на самом деле был и подвис, потому что NODE его не обработала никак. Соответственно, в log все будет попадать только по окончанию запроса.

BodyParser занимается тем, что считывает формы, которые присланы методом post, считывает JSON-данные, которые присланы этим методом.  То есть, разбирает тело запроса. Данные, переданные через post и аналогичные методы, считываются при помощи потоков. Это асинхронное действие.  BodyParser все это берет на себя, полностью считывает post, если это  JSON, тогда он его parse, и данные становятся доступны в req.body:

app.use(express.bodyParser());  // req.body....

После того, как он полностью прочитал post, этот Middleware передает управление дальше через next.

CookieParser тоже парсит, но не тело, а cookies. То есть, есть такие заголовки: req.headers. Оно их  разбирает и делает соответствующие свойства объекта cookies:

app.use(express.cookieParser('your secret here')); // req.cookies

Здесь можно указать необязательный ключ, которым cookies будут подписываться. Сейчас нам эта подпись не нужна, мы поговорим о ней позже.

Router позволяет нам удобным образом говорить, какие запросы будут и  как обработаны. Например добавим такой код:

app.use(app.router);

app.get('/', function(req, res, next) {
  res.end("Test")
});

Соответственно, вместо get может быть post, put, del и т.д. Кроме того, в этом Middleware есть еще дополнительные возможности (можно передать параметры и т.д.).

Последний Middleware это static. Обычно выдачей static занимаются другие сервера, не Node.js, но он тоже может это делать. То есть, если никакие Middleware отсюда запрос не обработали, тогда управление передается Middleware static.

app.use(express.static(path.join(__dirname, 'public')));

Он смотрит, есть ли в директории  public соответствующий файл. слегка переименуем директории в public (stylesheets-> css, javascript->js). Запускаем, работает!

App.js у нас теперь выглядит так, проверьте:

var express = require('express');
var http = require('http');
var path = require('path');
var config = require('config');
var log = require('libs/log')(module);


var app = express();
app.set('views', __dirname + '/templates');
app.set('view engine', 'ejs');

app.use(express.favicon()); // /favicon.ico
if (app.get('env') == 'development') {
  app.use(express.logger('dev'));
} else {
  app.use(express.logger('default'));
}

app.use(express.bodyParser());
app.use(express.cookieParser());

app.use(app.router);

app.get('/', function(req, res, next) {
  res.end("Test")
});

app.use(express.static(path.join(__dirname, 'public')));

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

// var routes = require('./routes');
// var user = require('./routes/user');

// // all environments

// app.get('/', routes.index);
// app.get('/users', user.list);


http.createServer(app).listen(config.get('port'), function(){
  log.info('Express server listening on port ' + config.get('port'));
});

Напоследок, вместо такого простого сообщения выведем нормальную HTML страницу. Для этого я в директории  template создам новый файл, назовем его index.ejs. Расширение файла  ejs, потому что шаблон к ejs так обычно делают. Сам шаблон представляет собой HTML, плюс дополнительно можно использовать такие специальные разделители, для того чтобы вставлять, например, код или переменные:

<!DOCTYPE html>
<html>
<head>
  <title>Hello, World!</title>
</head>
<body>
<section class="container">

  <h1>Hello, World!</h1>

  <%=body%>
  <%-body%>

</section>
</body>
</html>

Более подробно можем посмотреть в документации. Например, если говорить предметно, то вот такой вот код:

<% if (user) { %> 
   <h2><%= user.name %></h2>   
<% } %> 

<% if (user) { означает вставка просто JavaScript кода, то есть, выполнится оператор if, а %= означает вставку значения переменной.  <%-body%> тоже вставка переменной, но здесь, если в  body какой-то небезопасный текст (например <script>), то так <%-body%> он ставится как есть, а если <%=body%>, то он будет заменен на безопасные символы.

Давайте сделаем для примера так:

 <%=body%>
  <%-body%>

Конечно, нужно передать переменную в шаблон. Как это сделать? Очень просто, пишем в app.js:

app.get('/', function(req, res, next) {
  res.render("index", {
    body: '<b>Hello</b>'
  });
});

Проверяем. Заходим на

http://localhost:3000/

html

Вот, первое body была вставлено со знаком =, а второе со знаком -

У нас есть простейший сайт на Express, вывод в шаблон переменных. В следующей статье мы еще немного поработаем с шаблонами, с front-end частью, а потом перейдем к работе с данными.

Код урока доступен по ссылке.
staytuned2

Материалы для статьи взяты из следующего скринкаста.

4. Уроки Node.js. Структура Пакета NPM

Продолжаем наш разговор об NPM.Для того чтобы посмотреть на реальный package.json поставим модуль express. Введем в консоли:

npm i [email protected]

Этим модулем мы будем еще пользоваться в будущем, а сейчас мы просто ставим этот внешний модуль и посмотрим на его package.json, как он выглядит. Обнаружим там массу всего интересного.

Мы кратко пройдемся по некоторым особенностям package.json пока что в общих чертах, в дальнейшем, когда мы будем делать конкретные вещи, то используем это для решения конкретных задач. Итак, поля.

Leave a Reply