vps

نحوه اضافه کردن عکسهای پیشرفته در Node و Express

مقدمه
گاهی در هنگام ساختن برنامه Node خود با آپلود یک عکس (معمولاً از یک فرم) روبرو شده ایم که به عنوان عکس پروفایل برای کاربر در برنامه ما استفاده شود. علاوه بر این ، معمولاً برای دسترسی آسان باید عکس را در سیستم فایل محلی (در حین توسعه) یا حتی در ابر ذخیره کنیم. از آنجایی که این یک کار بسیار متداول است ، ابزارهای زیادی در دسترس است که می توانیم برای کنترل تک تک قسمتهای این فرآیند ، اهرم کنیم.
در این آموزش خواهیم دید که چگونه عکس را آپلود کرده و آن را قبل از نوشتن آن برای ذخیره سازی دستکاری کنید (تغییر اندازه ، کراپ ، سیاه سفید و غیره). ما برای سادگی خود را به ذخیره سازی فایل ها در سیستم فایل محلی محدود خواهیم کرد.
پیش نیازها
برای ساخت برنامه خود از بسته های زیر استفاده خواهیم کرد:
⦁ Express: یک سرور مجازی Node بسیار محبوب.
⦁ Lodash: یک کتابخانه بسیار مشهور JavaScript با بسیاری از کارکردهای مفید برای کار با آرایه ها ، رشته ها ، اشیاء و برنامه نویسی کاربردی.
⦁ Multer: بسته ای برای اکسترکت فایل ها از درخواست های multipart/form-data.
⦁ Jimp: بسته دستکاری تصویر.
⦁ Dotenv: بسته ای برای اضافه کردن متغیرهای .env به process.env.
⦁ Mkdirp: بسته ای برای ایجاد ساختار دایرکتوری تو در تو.
⦁ concat-stream: بسته ای برای ایجاد یک جریان قابل نوشتار که همه داده ها را از یک جریان جمع می کند و با نتیجه یک callback را فراخوانی میکند.
⦁ Streamifier : بسته ای برای تبدیل یک بافر / رشته به یک جریان قابل خواندن است.
اهداف پروژه
ما می خواهیم جریان فایل بارگذاری شده را از Multer دریافت کنیم و سپس بافر جریان (تصویر) را دستکاری کنیم ، اما می خواهیم قبل از نوشتن تصویر برای ذخیره سازی (سیستم فایل محلی) از Jimp استفاده کنیم . این امر مستلزم این است که یک موتور ذخیره سازی سفارشی ایجاد کنیم تا از Multer استفاده کند – که ما در این آموزش انجام خواهیم داد.
در این لینک، نتیجه نهایی آنچه در این آموزش خواهیم ساخت آمده است:
مرحله 1 – شروع کار
ما با ایجاد یک برنامه Express جدید با استفاده از ژنراتور Express شروع خواهیم کرد. اگر ژنراتور Express را از قبل ندارید ، باید ابتدا با اجرای دستور زیر در ترمینال خط فرمان خود آن را نصب کنید:
⦁ $ npm install express-generator -g

پس از تولید ژنراتور Express ، اکنون می توانید دستورات زیر را برای ایجاد یک برنامه Express جدید اجرا کنید و متعلقات Express را نصب کنید. ما از ejs به عنوان موتور نمایش استفاده خواهیم کرد:
⦁ $ express –view=ejs photo-uploader-app

⦁ $ cd photo-uploader-app

⦁ $ npm install

در مرحله بعد ، ما باقی مانده های متعلقات مورد نیاز برای پروژه خود را نصب خواهیم کرد:
⦁ $ npm install –save lodash multer jimp dotenv concat-stream streamifier mkdirp

مرحله 2 – پیکربندی اصول
قبل از ادامه ، برنامه ما به پیکربندی فرم نیاز دارد. یک فایل .env را در دیرکتوری اصلی پروژه خود ایجاد می کنیم و برخی از متغیرهای محیط را اضافه می کنیم. فایل .env باید مانند زیر باشد.
AVATAR_FIELD=avatar
AVATAR_BASE_URL=/uploads/avatars
AVATAR_STORAGE=uploads/avatars

در مرحله بعد ، متغیرهای محیطی خود را با استفاده از dotenv به process.env لود خواهیم کرد تا بتوانیم در برنامه خود به آنها دسترسی پیدا کنیم. برای این کار خط زیر را به فایل app.js اضافه خواهیم کرد. اطمینان حاصل کنید که این خط را در نقطه ای که اضافه کنید که متعلقات لود میشوند. باید قبل از ورودی دادن به تمام مسیرها و قبل از ایجاد نمونه برنامه Express اضافه شود.
app.js
var dotenv = require(‘dotenv’).config();

اکنون می توانیم با استفاده از process.env به متغیرهای محیطی خود دسترسی پیدا کنیم. به عنوان مثال: process.env.AVATAR_STORAGE باید دارای مقدار uploads/avatars باشد. ما در ادامه به ویرایش فایل مسیر ایندکس routes/index.js میپردازیم تا برخی متغیرهای محلی را که از نظر ما به آنها نیاز خواهیم داشت ، اضافه کنیم. دو متغیر محلی اضافه خواهیم کرد:
• title: عنوان صفحه فهرست ما: Upload Avatar
• avatar_field: نام فیلد ورودی برای عکس avatar ما. ما این را از process.env.AVATAR_FIELD دریافت خواهیم کرد .
مسیر GET / را به شرح زیر اصلاح کنید:
routes/index.js
router.get(‘/’, function(req, res, next) {
res.render(‘index’, { title: ‘Upload Avatar’, avatar_field: process.env.AVATAR_FIELD });
});

مرحله 3 – آماده سازی نما
بیایید با ایجاد نشانه گذاری پایه در فرم آپلود عکس خود با تغییر فایل views/index.ejs شروع کنیم. به خاطر سادگی ، سبک ها را مستقیماً به نمای خود اضافه خواهیم کرد تا ظاهری کمی زیبا به آن بخشیده شود. برای نشانه گذاری صفحه کد زیر را مشاهده کنید.
views/index.ejs
<html class=”no-js”>
<head>
<meta charset=”utf-8″>
<meta http-equiv=”X-UA-Compatible” content=”IE=edge”>
<meta name=”viewport” content=”width=device-width, initial-scale=1″>
<title><%= title %></title>
<style type=”text/css”>
* {
font: 600 16px system-ui, sans-serif;
}
form {
width: 320px;
margin: 50px auto;
text-align: center;
}
form > legend {
font-size: 36px;
color: #3c5b6d;
padding: 150px 0 20px;
}
form > input[type=file], form > input[type=file]:before {
display: block;
width: 240px;
height: 50px;
margin: 0 auto;
line-height: 50px;
text-align: center;
cursor: pointer;
}
form > input[type=file] {
position: relative;
}
form > input[type=file]:before {
content: ‘Choose a Photo’;
position: absolute;
top: -2px;
left: -2px;
color: #3c5b6d;
font-size: 18px;
background: #fff;
border-radius: 3px;
border: 2px solid #3c5b6d;
}
form > button[type=submit] {
border-radius: 3px;
font-size: 18px;
display: block;
border: none;
color: #fff;
cursor: pointer;
background: #2a76cd;
width: 240px;
margin: 20px auto;
padding: 15px 20px;
}
</style>
</head>
<body>
<form action=”/upload” method=”POST” enctype=”multipart/form-data”>
<legend>Upload Avatar</legend>
<input type=”file” name=”<%= avatar_field %>”>
<button type=”submit” class=”btn btn-primary”>Upload</button>
</form>
</body>
</html>

توجه کنید که چگونه از متغیرهای محلی در نمای خود استفاده کرده ایم تا عنوان و نام قسمت ورودی آواتار را تنظیم کنیم. متوجه می شوید که از enctype = “multipart / form-data” روی فرم خود استفاده می کنیم زیرا ما آپلود یک فایل را انجام خواهیم داد. همچنین خواهید دید که ما فرمی را تنظیم کرده ایم که درخواست POST را در حین ارائه به مسیر /upload بدهد (بعداً اجرا خواهیم کرد).
اکنون بیایید اولین بار برنامه را با استفاده از شروع npm شروع کنیم.
⦁ $ npm start

اگر به طور صحیح دنبال کرده باشید ، همه چیز بدون خطا باید اجرا شود. فقط از localhost: 3000 در مرورگر خود بازدید کنید. صفحه باید مانند تصویر زیر باشد:

مرحله 4 – ایجاد موتور ذخیره سازی Multer
تا اینجا ، تلاش برای بارگذاری عکس از طریق فرم ما منجر به خطایی خواهد شد زیرا ما نگه دارنده ای را برای درخواست بارگذاری ایجاد نکرده ایم. ما قصد داریم مسیر /upload را اجرا کنیم تا در واقع آپلود را مدیریت کنیم و برای آن از بسته Multer استفاده خواهیم کرد. اگر قبلاً با بسته Multer آشنا نبودید می توانید بسته Multer را در Github بررسی کنید.
ما باید یک موتور ذخیره سازی سفارشی ایجاد کنیم تا از آن با Multer استفاده کنیم. بیایید یک پوشه جدید در ریشه پروژه خود با نام helpers ایجاد کنیم و یک فایل جدید AvatarStorage.js در داخل آن برای موتور ذخیره سازی سفارشی ایجاد نماییم. فایل باید حاوی قطعه کد زیر باشد:
helpers/AvatarStorage.js
// Load dependencies
var _ = require(‘lodash’);
var fs = require(‘fs’);
var path = require(‘path’);
var Jimp = require(‘jimp’);
var crypto = require(‘crypto’);
var mkdirp = require(‘mkdirp’);
var concat = require(‘concat-stream’);
var streamifier = require(‘streamifier’);

// Configure UPLOAD_PATH
// process.env.AVATAR_STORAGE contains uploads/avatars
var UPLOAD_PATH = path.resolve(__dirname, ‘..’, process.env.AVATAR_STORAGE);

// create a multer storage engine
var AvatarStorage = function(options) {

// this serves as a constructor
function AvatarStorage(opts) {}

// this generates a random cryptographic filename
AvatarStorage.prototype._generateRandomFilename = function() {}

// this creates a Writable stream for a filepath
AvatarStorage.prototype._createOutputStream = function(filepath, cb) {}

// this processes the Jimp image buffer
AvatarStorage.prototype._processImage = function(image, cb) {}

// multer requires this for handling the uploaded file
AvatarStorage.prototype._handleFile = function(req, file, cb) {}

// multer requires this for destroying file
AvatarStorage.prototype._removeFile = function(req, file, cb) {}

// create a new instance with the passed options and return it
return new AvatarStorage(options);

};

// export the storage engine
module.exports = AvatarStorage;

بیایید شروع به اضافه کردن دستورات برای توابع ذکر شده در موتور ذخیره سازی کنیم. با تابع سازنده شروع خواهیم کرد.
// this serves as a constructor
function AvatarStorage(opts) {

var baseUrl = process.env.AVATAR_BASE_URL;

var allowedStorageSystems = [‘local’];
var allowedOutputFormats = [‘jpg’, ‘png’];

// fallback for the options
var defaultOptions = {
storage: ‘local’,
output: ‘png’,
greyscale: false,
quality: 70,
square: true,
threshold: 500,
responsive: false,
};

// extend default options with passed options
var options = (opts && _.isObject(opts)) ? _.pick(opts, _.keys(defaultOptions)) : {};
options = _.extend(defaultOptions, options);

// check the options for correct values and use fallback value where necessary
this.options = _.forIn(options, function(value, key, object) {

switch (key) {

case ‘square’:
case ‘greyscale’:
case ‘responsive’:
object[key] = _.isBoolean(value) ? value : defaultOptions[key];
break;

case ‘storage’:
value = String(value).toLowerCase();
object[key] = _.includes(allowedStorageSystems, value) ? value : defaultOptions[key];
break;

case ‘output’:
value = String(value).toLowerCase();
object[key] = _.includes(allowedOutputFormats, value) ? value : defaultOptions[key];
break;

case ‘quality’:
value = _.isFinite(value) ? value : Number(value);
object[key] = (value && value >= 0 && value <= 100) ? value : defaultOptions[key];
break;

case ‘threshold’:
value = _.isFinite(value) ? value : Number(value);
object[key] = (value && value >= 0) ? value : defaultOptions[key];
break;

}

});

// set the upload path
this.uploadPath = this.options.responsive ? path.join(UPLOAD_PATH, ‘responsive’) : UPLOAD_PATH;

// set the upload base url
this.uploadBaseUrl = this.options.responsive ? path.join(baseUrl, ‘responsive’) : baseUrl;

if (this.options.storage == ‘local’) {
// if upload path does not exist, create the upload path structure
!fs.existsSync(this.uploadPath) && mkdirp.sync(this.uploadPath);
}

}

در اینجا ، تابع سازنده خود را برای پذیرش چند گزینه تعریف کردیم. همچنین در صورت عدم ارائه یا عدم اعتبار ، مقادیر پیش فرض (برگشت پذیر) را برای این گزینه ها اضافه کردیم. می توانید بسته به آنچه می خواهید ، گزینه های بیشتری را برای این کار تنظیم کنید ، اما برای این آموزش ما گزینه های زیر را برای موتور ذخیره سازی خود استفاده خواهیم کرد.
⦁ storage: سیستم فایل ذخیره سازی است. مقدار مجاز برای سیستم فایل محلی فقط local است. پیش فرض “local” قرار دارد. در صورت تمایل می توانید سایر سیستم های ذخیره سازی فایل (مانند Amazon S3) را پیاده سازی کنید.
⦁ output: فرمت خروجی تصویر است. می تواند “jpg” یا “png” باشد. پیش فرض”png” است.
⦁ Greyscale: در صورت تنظیم روی true ، تصویر خروجی سیاه سفید خواهد بود. پیش فرض روی false است.
⦁ quality: عددی بین 0تا 100 که کیفیت تصویر خروجی را تعیین می کند. پیش فرض 70 است.
⦁ square: اگر روی true باشد ، تصویر به یک مربع بریده می شود. پیش فرض روی false است.
⦁ threshold: عددی که کوچکترین بعد (برحسب پیکسل) تصویر خروجی را محدود می کند. مقدار پیش فرض 500 است. اگر کوچکترین بعد تصویر از این عدد تجاوز کند ، اندازه تغییر می کند به طوری که کوچکترین ابعاد برابر آستانه است.
⦁ responsive: در صورت تنظیم روی true ، سه تصویر خروجی در اندازه های مختلف (lg ، md و sm) در پوشه های مربوطه خود ایجاد و ذخیره می شوند. پیش فرض روی false است.
بیایید روش های ایجاد نام فایل های تصادفی و جریان خروجی را برای نوشتن روی فایل ها را پیاده کنیم:
// this generates a random cryptographic filename
AvatarStorage.prototype._generateRandomFilename = function() {
// create pseudo random bytes
var bytes = crypto.pseudoRandomBytes(32);

// create the md5 hash of the random bytes
var checksum = crypto.createHash(‘MD5’).update(bytes).digest(‘hex’);

// return as filename the hash with the output extension
return checksum + ‘.’ + this.options.output;
};

// this creates a Writable stream for a filepath
AvatarStorage.prototype._createOutputStream = function(filepath, cb) {

// create a reference for this to use in local functions
var that = this;

// create a writable stream from the filepath
var output = fs.createWriteStream(filepath);

// set callback fn as handler for the error event
output.on(‘error’, cb);

// set handler for the finish event
output.on(‘finish’, function() {
cb(null, {
destination: that.uploadPath,
baseUrl: that.uploadBaseUrl,
filename: path.basename(filepath),
storage: that.options.storage
});
});

// return the output stream
return output;
};

در اینجا ، ما از crypto برای ایجاد یک hash md5 تصادفی استفاده می کنیم تا از نام فایل استفاده شود و خروجی را از گزینه ها به عنوان پسوند فایل ضمیمه کنیم. همچنین روش کمکی خود را برای ایجاد جریان قابل نوشتار از filepath مشخص شده تعریف کرده و سپس جریان را برگردانده ایم. توجه داشته باشید که یک تابع callback لازم است ، زیرا ما از آن در مدیریت رویداد جریان استفاده می کنیم.
در ادامه روش _processImage () را که پردازش تصویر واقعی را انجام می دهد ، پیاده خواهیم کرد. در اینجا این پیاده سازی آمده است:
// this processes the Jimp image buffer
AvatarStorage.prototype._processImage = function(image, cb) {

// create a reference for this to use in local functions
var that = this;

var batch = [];

// the responsive sizes
var sizes = [‘lg’, ‘md’, ‘sm’];

var filename = this._generateRandomFilename();

var mime = Jimp.MIME_PNG;

// create a clone of the Jimp image
var clone = image.clone();

// fetch the Jimp image dimensions
var width = clone.bitmap.width;
var height = clone.bitmap.height;
var square = Math.min(width, height);
var threshold = this.options.threshold;

// resolve the Jimp output mime type
switch (this.options.output) {
case ‘jpg’:
mime = Jimp.MIME_JPEG;
break;
case ‘png’:
default:
mime = Jimp.MIME_PNG;
break;
}

// auto scale the image dimensions to fit the threshold requirement
if (threshold && square > threshold) {
clone = (square == width) ? clone.resize(threshold, Jimp.AUTO) : clone.resize(Jimp.AUTO, threshold);
}

// crop the image to a square if enabled
if (this.options.square) {

if (threshold) {
square = Math.min(square, threshold);
}

// fetch the new image dimensions and crop
clone = clone.crop((clone.bitmap.width: square) / 2, (clone.bitmap.height: square) / 2, square, square);
}

// convert the image to greyscale if enabled
if (this.options.greyscale) {
clone = clone.greyscale();
}

// set the image output quality
clone = clone.quality(this.options.quality);

if (this.options.responsive) {

// map through the responsive sizes and push them to the batch
batch = _.map(sizes, function(size) {

var outputStream;

var image = null;
var filepath = filename.split(‘.’);

// create the complete filepath and create a writable stream for it
filepath = filepath[0] + ‘_’ + size + ‘.’ + filepath[1];
filepath = path.join(that.uploadPath, filepath);
outputStream = that._createOutputStream(filepath, cb);

// scale the image based on the size
switch (size) {
case ‘sm’:
image = clone.clone().scale(0.3);
break;
case ‘md’:
image = clone.clone().scale(0.7);
break;
case ‘lg’:
image = clone.clone();
break;
}

// return an object of the stream and the Jimp image
return {
stream: outputStream,
image: image
};
});

} else {

// push an object of the writable stream and Jimp image to the batch
batch.push({
stream: that._createOutputStream(path.join(that.uploadPath, filename), cb),
image: clone
});

}

// process the batch sequence
_.each(batch, function(current) {
// get the buffer of the Jimp image using the output mime type
current.image.getBuffer(mime, function(err, buffer) {
if (that.options.storage == ‘local’) {
// create a read stream from the buffer and pipe it to the output stream
streamifier.createReadStream(buffer).pipe(current.stream);
}
});
});

};

در این روش کارهای زیادی در حال انجام است اما خلاصه ای از کارهایی که انجام می شود در اینجا آمده است:
⦁ یک نام فایل تصادفی ایجاد می کند ، نوع mime تصویر خروجی Jimp را برطرف می کند و ابعاد تصویر را بدست می آورد.
⦁ در صورت لزوم ، براساس نیازهای ابعاد آستانه ، اندازه را تغییر میدهد تا اطمینان حاصل شود که کوچکترین ابعاد از آستانه تجاوز نمی کند.
⦁ اگر در گزینه ها فعال باشد ، تصویر را به یک مربع برش میدهد.
⦁ در صورت فعال بودن در گزینه ها ، تصویر را به مقیاس خاکستری تبدیل کنید.
⦁ کیفیت خروجی تصویر را از گزینه ها تنظیم کنید.
⦁ در صورت فعال بودن گزینه پاسخگو ، تصویر برای هر یک از اندازه های پاسخگو (lg ، md و sm) کلون شده و مقیاس بندی می شود و سپس یک جریان خروجی با استفاده از روش _createOutputStream () برای هر فایل تصویر در اندازه های مربوطه ایجاد می شود. نام فایل برای هر اندازه ، قالب [random_filename_hash]_[size].[output_extension] را می گیرد. سپس کلون تصویر و جریان در دسته ای برای پردازش قرار می گیرند.
⦁ اگر گزینه پاسخگو غیرفعال باشد ، فقط تصویر فعلی و یک جریان خروجی برای آن در دسته ای برای پردازش قرار می گیرد.
⦁ سرانجام ، با تبدیل یک بافر تصویر Jimp  به یک جریان قابل خواندن با استفاده از streamifier و سپس لوله زنی جریان قابل خواندن به جریان خروجی ، هر مورد در دسته ای پردازش می شود.
اکنون روش های باقی مانده را پیاده سازی می کنیم و با موتور ذخیره سازی کار را به پایان میرسانیم.
// multer requires this for handling the uploaded file
AvatarStorage.prototype._handleFile = function(req, file, cb) {

// create a reference for this to use in local functions
var that = this;

// create a writable stream using concat-stream that will
// concatenate all the buffers written to it and pass the
// complete buffer to a callback fn
var fileManipulate = concat(function(imageData) {

// read the image buffer with Jimp
// it returns a promise
Jimp.read(imageData)
.then(function(image) {
// process the Jimp image buffer
that._processImage(image, cb);
})
.catch(cb);
});

// write the uploaded file buffer to the fileManipulate stream
file.stream.pipe(fileManipulate);

};

// multer requires this for destroying file
AvatarStorage.prototype._removeFile = function(req, file, cb) {

var matches, pathsplit;
var filename = file.filename;
var _path = path.join(this.uploadPath, filename);
var paths = [];

// delete the file properties
delete file.filename;
delete file.destination;
delete file.baseUrl;
delete file.storage;

// create paths for responsive images
if (this.options.responsive) {
pathsplit = _path.split(‘/’);
matches = pathsplit.pop().match(/^(.+?)_.+?\.(.+)$/i);

if (matches) {
paths = _.map([‘lg’, ‘md’, ‘sm’], function(size) {
return pathsplit.join(‘/’) + ‘/’ + (matches[1] + ‘_’ + size + ‘.’ + matches[2]);
});
}
} else {
paths = [_path];
}

// delete the files from the filesystem
_.each(paths, function(_path) {
fs.unlink(_path, cb);
});

};

موتور ذخیره سازی ما اکنون آماده استفاده با Multer است.
مرحله 5 – اجرای مسیر POST /upload
قبل از اینکه مسیر را تعیین کنیم ، باید Multer را برای استفاده در مسیر خود تنظیم کنیم. بیایید برای ویرایش فایل routes/index.js پیش برویم و موارد زیر را اضافه کنیم:
routes/index.js
var express = require(‘express’);
var router = express.Router();

/**
* CODE ADDITION
*
* The following code is added to import additional dependencies
* and setup Multer for use with the /upload route.
*/

// import multer and the AvatarStorage engine
var _ = require(‘lodash’);
var path = require(‘path’);
var multer = require(‘multer’);
var AvatarStorage = require(‘../helpers/AvatarStorage’);

// setup a new instance of the AvatarStorage engine
var storage = AvatarStorage({
square: true,
responsive: true,
greyscale: true,
quality: 90
});

var limits = {
files: 1, // allow only 1 file per request
fileSize: 1024 * 1024, // 1 MB (max file size)
};

var fileFilter = function(req, file, cb) {
// supported image file mimetypes
var allowedMimes = [‘image/jpeg’, ‘image/pjpeg’, ‘image/png’, ‘image/gif’];

if (_.includes(allowedMimes, file.mimetype)) {
// allow supported image files
cb(null, true);
} else {
// throw error for invalid files
cb(new Error(‘Invalid file type. Only jpg, png and gif image files are allowed.’));
}
};

// setup multer
var upload = multer({
storage: storage,
limits: limits,
fileFilter: fileFilter
});

/* CODE ADDITION ENDS HERE */

در اینجا ، قادر به برش مربع ، تصاویر پاسخگو و تنظیم ابعاد آستانه برای موتور ذخیره سازی خود هستیم. همچنین برای اطمینان از حداکثر اندازه 1 مگابایت و اطمینان از عدم بارگذاری فایل های غیر تصویری ، محدودیت هایی در تنظیمات Multer خود اضافه می کنیم.
اکنون بیایید مسیر POST /upload را به شرح زیر اضافه کنیم:
/* routes/index.js */

/**
* CODE ADDITION
*
* The following code is added to configure the POST /upload route
* to upload files using the already defined Multer configuration
*/

router.post(‘/upload’, upload.single(process.env.AVATAR_FIELD), function(req, res, next) {

var files;
var file = req.file.filename;
var matches = file.match(/^(.+?)_.+?\.(.+)$/i);

if (matches) {
files = _.map([‘lg’, ‘md’, ‘sm’], function(size) {
return matches[1] + ‘_’ + size + ‘.’ + matches[2];
});
} else {
files = [file];
}

files = _.map(files, function(file) {
var port = req.app.get(‘port’);
var base = req.protocol + ‘://’ + req.hostname + (port ? ‘:’ + port : ”);
var url = path.join(req.file.baseUrl, file).replace(/[\\\/]+/g, ‘/’).replace(/^[\/]+/g, ”);

return (req.file.storage == ‘local’ ? base : ”) + ‘/’ + url;
});

res.json({
images: files
});

});

/* CODE ADDITION ENDS HERE */

توجه کنید که چگونه ما از میان افزار بارگذاری Multer قبل از کنترل مسیر خود عبور کردیم. روش single () به ما اجازه می دهد تا فقط یک فایل را که در req.file ذخیره می شود بارگذاری کنیم. به عنوان اولین پارامتر ، نام فیلد ورودی فایل را میگیرد که از process.env.AVATAR_FIELD به آن دسترسی پیدا می کنیم.
اکنون بیایید برنامه را با استفاده از شروع npm دوباره شروع کنیم.
⦁ $ npm start

به localhost: 3000 در مرورگر خود مراجعه کرده و سعی کنید عکسی بارگذاری کنید. در اینجا نمونه ای از عکسی از تست مسیر بارگذاری در Postman با استفاده از گزینه های تنظیمات فعلی ما اسکرین شات گرفته ام آمده است:

می توانید گزینه های پیکربندی موتور ذخیره سازی را در تنظیمات Multer مورد نظر خود قرار دهید تا نتایج مختلفی کسب کنید.
نتیجه
در این آموزش ، ما توانسته ایم موتور ذخیره سازی سفارشی را برای استفاده با Multer ایجاد کنیم که تصاویر بارگذاری شده را با استفاده از Jimp دستکاری کرده و سپس آنها را برای ذخیره سازی می نویسد. برای نمونه کامل کد این آموزش ، منبع  advanced-multer-node-sourcecode در Github را بررسی کنید.

 

از این لینک ها زیر می توانید آمورش های بیشتری برای لینوکس پیدا کنید :

استفاده از nsh برای دستورات از راه دور اوبونتو 18 –  میزبانی وب سایت با Caddy اوبونتو 18

تنظیم سرور ذخیره سازی آبجکت با استفاده از Minio در اوبونتو 18  –  ضبط و اشتراک گذاری ترمینال با Terminalizer اوبونتو

تنظیم مسیریابی شرطی و پاسخگو با React Router v4  –  ایجاد یک URL کوتاه کننده با Django و GraphQL

یک برنامه ردیابی سلامت را با React ،GraphQL و Okta –  ساخت برنامه چت زمان حقیقی React و GraphQL

به روزرسانی فیلترهای مرتب سازی Angular (زاویه ای) –  با استفاده از React ، Superagent و API اینستاگرام

نحوه ساختن یک برنامه جهانی با Nuxt.js و Django –  دکمه دانلود با ریزتعاملات با CSS ، anime.js و segment.js

نحوه اضافه کردن عکسهای پیشرفته در Node و Express  –  با Vue ،GraphQL و Apollo Client یک وبلاگ ساخت

یک برنامه SSR با روتر Preact ، Unistore و Preact بسازید  –  ساخت برنامه های وب پیشرونده با Angular

اشکال زدایی JavaScript در تولید با نقشه های منبع  –  می توان با Koa برنامه “سلام جهانی” ساخت

ساختن یک برنامه با Node ، React ، Okta  –   مدیریت حالت فرم در React با Redux Form

نحوه تنظیم Laravel ، Nginx و MySQL  –  ارتقاء از AngularJS به Angular با ngUpgrade

استفاده از ویژوال استودیو از راه دور  –  احراز هویت API با JSON Web Tokens و Passport

راه اندازی یک پروژه React با Parcel  –  ایجاد Swiper مانند Netflix را در Vue

ساختن یک ربات تلگرام با Laravel و BotMan  –  استفاده از map، filter، و reduce در جاوااسکریپت

چگونه می توان موتور جستجوی زمان واقعی را با Vue  –  ساختن سیستم مستندات (Documentation) با Vue و VuePress

استفاده از اشتراک زنده با کد ویژوال استودیو  –  ساخت یک مقیاس اندازه گیری قدرت رمز عبور را در React

شروع عملی GraphQL با Node.js و Express  –  ساخت یک برنامه آب و هوا در Django

نحوه نصب Discourse روی Ubuntu 18  –  تأیید رمز عبور با استفاده از درخواست فرم Laravel

نحوه نصب MySQL در CentOS 8  –  استفاده از پسوند PDO PHP برای انجام تراکنش MySQL

نصب و پیکربندی SNMP Daemon و Client در Ubuntu 18  –  نصب Linux، Nginx، MariaDB،PHP در Debian 10

 

 

کلمات کلیدی خرید سرور

خرید vps – خرید سرور مجازی – خرید سرور – سرور هلند – فروش vps – سرور مجازی آمریکا – خریدvps – سرور مجازی هلند – فروش سرور مجازی – سرور آمریکا – vps – سرور مجازی انگلیس – سرور مجازی آلمان – سرور مجازی کانادا – خرید vps آمریکا – خرید وی پی اس – سرور – خرید سرور مجازی هلند – vps خرید – سرور مجازی فرانسه – سرور مجازی هلند – خرید vps آمریکاخرید سرور مجازی ارزان هلندvpsخرید vps هلندخرید سرور مجازی آمریکاخرید vps فرانسهتست vpsسرور مجازی تستسرور مجازی ویندوزارزانترین vpsخرید وی پی اسvps ارزان – 


https://vpsgol.net/product/vps-germany/

https://vpsgol.net/product/vps-usa/

https://vpsgol.net/product/vps-france/

https://vpsgol.net/product/vps-canada/

https://vpsgol.net/product/vps-poland/

https://vpsgol.net/product/vps-netherlands/

https://vpsgol.net/product/vps-england/