В современном мире технологий микросервисы стали неотъемлемой частью веб-разработки. Микросервисы — это небольшие независимые приложения, которые могут взаимодействовать друг с другом для создания более крупных и сложных, но эффективных систем. Одним из распространенных вариантов использования микросервисов является хранение файлов. В этом сообщении блога мы обсудим, как настроить Total.js OpenFiles в качестве микросервиса хранения файлов для приложения Express в 3 шага:

  • сначала мы узнаем о Total.js OpenFiles, зачем он нам нужен и как его установить.
  • Во-вторых, мы увидим первый подход (плохой) того, как подключить Total.js OpenFiles как микросервис к экспресс-приложению.
  • И, наконец, мы увидим второй подход (хороший и рекомендуемый) того, как его подключить.

Эта запись в блоге включает как реализации кода, так и иллюстрации дизайна системы для лучшего понимания некоторых простых концепций системных микросервисных архитектур. Убедитесь, что вы дочитали до конца, чтобы не пропустить ни одного опыта разработки микросервисов.

Total.js OpenFiles

OpenFiles – это легкое приложение для хранения файлов из сторонних приложений. Приложение полностью построено с использованием Total.js Framework, и его функциональность проста: файлы хранятся на жестком диске в Total.js FileStorage, о котором мы говорили в моем предыдущем посте в блоге (Читать здесь). Кроме того, вы можете легко просматривать и фильтровать сохраненные файлы в интерфейсе установки OpenFiles.

Самое интересное в этом приложении — его API. Да, OpenFiles предоставляет API, который позволяет сторонним приложениям хранить в нем файлы.

Установка и настройка

Установить Total.js OpenFiles очень просто. Я подготовил обучающее видео о том, как его установить. Установка его на вашем компьютере необходима для остальной части этого руководства. Не забудьте ПОДПИСАТЬСЯ на мой канал.

Подключите OpenFiles к Express.js (метод 1)

Вот самая интересная часть урока. В предыдущем разделе мы следовали видеоруководству YouTube, и теперь у нас есть отличный микросервис для хранения файлов, работающий на нашем компьютере или где-либо еще. Теперь мы можем попробовать первый подход (плохой), чтобы заставить приложение express.js хранить файлы в этом файловом хранилище. Чтобы иметь четкое представление о том, что мы делаем, давайте сначала проиллюстрируем дизайн.

Системный дизайн

Реализация приложения express.js

Во-первых, нам нужно запустить простое приложение express.js и установить зависимости через npm.

# Create folder
$ mkdir expressapp && cd expressapp
# Init application
$ npm init -y
# Install dependencies
$ npm install express total4 multer ejs
# Create endpoint file
$ touch index.js
#create folder for views
$ mkdir views

Затем мы создаем серверное приложение express.js, помещая в index.js следующее:

require('total4');
const Express = require('express');
const multer = require('multer');
// URL of OpenFile instance + auth token (see video)
const Url = 'http://localhost:8000/upload/photos?token=yourtoken&hostname=1';

const app = Express();
const PORT = 3000;
const storage = multer.diskStorage({ 
    destination: function(req, file, cb) {
        return cb(null, 'temp')
    },
    filename: function(req, file, cb) {
        return cb(null, NOW.format('yyyyMMdd_HHmmss') + '_' + file.originalname)
    }
});

const upload = multer({ storage: storage });

app.set('view engine', 'ejs');
app.set('views', PATH.views());

app.use(Express.json());
app.get('/', function(req, res) {
    res.render('index', { info: '', url: '' });
});

app.post('/upload', upload.single('photo'), async function(req, res) {
   var data =  req.body;
   var file = req.file;
   var response;

   // Send file to The Total.js OpenFiles
   if (file) 
        response  = await RESTBuilder.POST(Url, { }).file('file', PATH.root(file.path)).promise();


    // save data
    data.id = UID();
    data.search = (data.name + ' ' + data.phone).toSearch();
    data.photo = response ? response.url : '';
    data.dtcreated = NOW;
    NOSQL('users').insert(data, true).callback(function(err, resp) {
        res.render('index', { info:response.name, url: response.url});
    });
});
app.listen(PORT);

Теперь нам нужно добавить index.ejs представление файла в папку views:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
 <meta http-equiv="X-UA-Compatible" content="IE=10" />
 <meta name="format-detection" content="telephone=no"/>
 <meta name="viewport" content="width=1024, user-scalable=yes" />
 <meta name="robots" content="all,follow" />
 <style type="text/css">
  body { padding: 50px; margin: 0; font:normal 12px Arial; color: gray }
  .paging { font-size: 11px; height: 20px }
  .paging a { float: left; margin-right: 5px; }
  .paging div { float: right; }
  .mb5 { margin-bottom: 5px; }
 </style>
</head>
<body>
<div style="background-color:#F0F0F0;padding:3px 10px">
 Uploaded: <b style="color:black"><%= info %></b>
 Image: <br>
 <% if (url) { %>
  <img src="<%= url %>" width="150" alt="Image preview">
 <% } %>
</div>
<br />
<form method="POST" enctype="multipart/form-data" action="/upload">
 <input type="text" name="name" placeholder="Name" /> <br><br>
 <input type="email" name="email" placeholder="Email" /><br><br>
 <input type="phone" name="phone" placeholder="Phone" /><br><br>
 <input type="file" name="photo" /><br><br><br>
 <button>SUBMIT</button>
</form>
</body>
</html>

Наконец, мы можем запустить наш сервер Express и провести несколько тестов:

$ node index.js

После некоторого тестирования вы должны увидеть простой пользовательский интерфейс, подобный этому:

Файл успешно загружен, и информация о пользователе также сохраняется в базе данных.
Однако у такого подхода к подключению микросервиса хранения файлов есть проблемы:

  • Использование экспресс-сервера для проксирования файла делает его медленным, потому что файл обрабатывается дважды, и DNS также разрешается дважды.
  • Можно было бы избежать включения multer в этот проект, чтобы сделать экспресс-приложение очень легким, а также избежать хранения файлов во временной папке.
  • Приводить total4 — очень плохая идея, Total.js — это самостоятельный фреймворк для веб-разработки. Перенос всего фреймворка Total.js в другой фреймворк (Express) работает нормально, но это не очень хорошая практика.

Этот первый подход работает нормально, но это не очень хорошая практика, что приводит нас ко второму подходу, который намного лучше.

Подключите OpenFiles к Express.js (метод 2)

У первого метода есть некоторые недостатки, поэтому мы изменим дизайн нашей системы, чтобы улучшить микросервисную архитектуру.

Системный дизайн

На этот раз мы отправляем файл из веб-браузера в наш микросервис Total.js OpenFiles. Он вернет URL-адрес, и мы сможем передать URL-адрес и данные формы в наше экспресс-приложение. Как на следующей иллюстрации:

Реализация приложения express.js

Теперь, когда мы не отправляем файлы в OpenFiles через экспресс-приложение, экспресс-приложение стало проще и лучше. Файл index.js упрощен следующим образом:

require('total4');
const Express = require('express');

const app = Express();
const PORT = 3000;

app.set('view engine', 'ejs');
app.set('views', PATH.views());

app.use(Express.json());
app.get('/', function(req, res) {
    res.render('index', { info: 'info', url: '' });
});

app.post('/upload', async function(req, res) {
   var data =  req.body;
   console.log(data);
    // save data
    data.id = UID();
    data.search = (data.name + ' ' + data.phone).toSearch();
    data.dtcreated = NOW;
    NOSQL('users').insert(data, true).callback(function(err, resp) {
        res.json({ success: true, value: data.id });
    });
});


app.listen(PORT);

PS: у нас все еще есть require('total4') только из-за базы данных NOSQL, которую мы используем, но если вы хотите использовать базу данных Mysql, как описано в дизайне системы, то total4 совершенно бесполезна. Затем у вас есть следующее в файле views/index.ejs:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
 <meta http-equiv="X-UA-Compatible" content="IE=10" />
 <meta name="format-detection" content="telephone=no"/>
 <meta name="viewport" content="width=1024, user-scalable=yes" />
 <meta name="robots" content="all,follow" />
 <script src="//cdn.componentator.com/[email protected]"></script>
 <link rel="stylesheet" href="//cdn.componentator.com/[email protected]" />
 <style type="text/css">
  body { padding: 50px; margin: 0; font:normal 12px Arial; color: gray }
  .paging { font-size: 11px; height: 20px }
  .paging a { float: left; margin-right: 5px; }
  .paging div { float: right; }
  .mb5 { margin-bottom: 5px; }
  .button { border: 0; margin: 15px 0 0; background-color: #F0F0F0; height: 34px; padding: 0 15px; color: #000; cursor: pointer; font-family: Arial; line-height: 34px; vertical-align: middle; outline: 0; font-size: 14px; text-decoration: none; transition: all 0.3s; float: left; width: 100%; }
  .button:disabled { background-color: #7c98d5; }
  .button i { width: 15px; text-align: center; margin-right: 5px; }
 </style>
</head>
<body>
<ui-component name="upload"></ui-component>
<br />


<div class="container">
 <ui-plugin name="Form" path="form" >
  <div class="grid-2">
   <ui-component name="input" path="?.name" config="required:1;">Name</ui-component>
   <ui-component name="input" path="?.email" config="required:1;type:email">Email</ui-component>
   <ui-component name="input" path="?.phone" config="required:1;type:phone">Phone</ui-component>
   <ui-component name="input" path="?.photo" config="required:1;type:url;disabled:1">Photo url</ui-component>
   <span></span>
   <ui-component name="preview" path="preview" config="width:300;height:200;url:[openfiles];icon:folder;preview:value => value.url;">Preview</ui-component>
  </div>
  <ui-component name="submit" path="?" config="url:POST /upload/">
   <button class="button" name="submit" disabled="disabled">SUBMIT FORM</button>
  </ui-component>
 </ui-plugin>
</div>
<script>
 var preview = {};
 var form = {};
 ENV('openfiles', 'http://localhost:8000/base64/photos?token=yourtoken&hostname=1');
 console.log(ENV());
 WATCH('preview', function(path, value) {
  SET('form.photo', value.url);
 });
</script>

</body>
</html>

На этот раз мы импортируем CDN в начале HTML-документа: это клиентская библиотека Total.js. Мы пытаемся использовать его мощные функции привязки данных и бесплатные компоненты пользовательского интерфейса для загрузки изображения прямо из браузера в микросервис OpenFiles. Вы должны увидеть следующий результат:

Таким образом, мы установили и изучили Total.js OpenFiles, прежде чем подключать его к приложению Express.js в качестве микросервиса, используя два разных подхода. Первый подход хорош, но со временем может стать проблематичным, особенно при масштабировании приложения. Второй подход не идеален, но, по крайней мере, решает многие проблемы, которые с большей вероятностью может решить первый подход. Я надеюсь, что это было полезно. Не стесняйтесь играть с кодом, подключать его к любому другому языку бэкенда, который вы хотите, и если вы обнаружите некоторые идеи о том, как улучшить любой из этих системных проектов, то не стесняйтесь оставлять некоторые комментарии. Ставьте лайки, делитесь и подписывайтесь.