Memilih antara platform NestJS + Fastify dan NestJS + Express, saya membuat pilihan terhadap NestJS + Fastify. Mengetahui kecenderungan pengembang dalam situasi apa pun yang tidak dapat dipahami untuk menggantung properti tambahan pada objek req di Express dan dengan demikian berkomunikasi di antara berbagai bagian aplikasi, saya dengan tegas memutuskan bahwa Express tidak akan ada di proyek berikutnya.
Saya hanya perlu menyelesaikan masalah teknis dengan Content-Type: multipart / form-data. Juga, saya berencana untuk menyimpan file yang diterima melalui Content-Type: permintaan data multipart / form-data di penyimpanan S3. Dalam hal ini, implementasi permintaan Content-Type: multipart / form-data pada platform NestJS + Express membuat saya bingung karena itu tidak berfungsi dengan aliran.
Meluncurkan Penyimpanan Lokal S3
S3 adalah penyimpanan data (bisa dikatakan, meskipun tidak tegasnya, penyimpanan file) dapat diakses melalui protokol http. S3 awalnya disediakan oleh AWS. API S3 saat ini juga didukung oleh layanan cloud lainnya. Tapi tidak hanya itu. Ada implementasi server S3 yang dapat Anda gunakan secara lokal untuk digunakan selama pengembangan, dan mungkin mengaktifkan dan menjalankan server S3 Anda dalam produksi.
Pertama, Anda perlu memutuskan motivasi untuk menggunakan penyimpanan data S3. Dalam beberapa kasus, ini dapat mengurangi biaya. Misalnya, Anda dapat menggunakan penyimpanan S3 paling lambat dan termurah untuk menyimpan cadangan. Penyimpanan cepat dengan lalu lintas tinggi (lalu lintas dibebankan secara terpisah) untuk memuat data dari penyimpanan mungkin akan berharga sebanding dengan drive SSD dengan ukuran yang sama.
Motif yang lebih kuat adalah 1) skalabilitas - Anda tidak perlu memikirkan fakta bahwa ruang disk mungkin habis, dan 2) keandalan - server bekerja dalam cluster dan Anda tidak perlu memikirkan tentang cadangan, karena jumlah salinan yang diperlukan selalu tersedia.
Untuk meningkatkan implementasi server S3 - minio - secara lokal Anda hanya perlu docker dan docker-compose yang diinstal di komputer. File docker-compose.yml yang sesuai:
version: '3'
services:
minio1:
image: minio/minio:RELEASE.2020-08-08T04-50-06Z
volumes:
- ./s3/data1-1:/data1
- ./s3/data1-2:/data2
ports:
- '9001:9000'
environment:
MINIO_ACCESS_KEY: minio
MINIO_SECRET_KEY: minio123
command: server http://minio{1...4}/data{1...2}
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live']
interval: 30s
timeout: 20s
retries: 3
minio2:
image: minio/minio:RELEASE.2020-08-08T04-50-06Z
volumes:
- ./s3/data2-1:/data1
- ./s3/data2-2:/data2
ports:
- '9002:9000'
environment:
MINIO_ACCESS_KEY: minio
MINIO_SECRET_KEY: minio123
command: server http://minio{1...4}/data{1...2}
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live']
interval: 30s
timeout: 20s
retries: 3
minio3:
image: minio/minio:RELEASE.2020-08-08T04-50-06Z
volumes:
- ./s3/data3-1:/data1
- ./s3/data3-2:/data2
ports:
- '9003:9000'
environment:
MINIO_ACCESS_KEY: minio
MINIO_SECRET_KEY: minio123
command: server http://minio{1...4}/data{1...2}
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live']
interval: 30s
timeout: 20s
retries: 3
minio4:
image: minio/minio:RELEASE.2020-08-08T04-50-06Z
volumes:
- ./s3/data4-1:/data1
- ./s3/data4-2:/data2
ports:
- '9004:9000'
environment:
MINIO_ACCESS_KEY: minio
MINIO_SECRET_KEY: minio123
command: server http://minio{1...4}/data{1...2}
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live']
interval: 30s
timeout: 20s
retries: 3
Kami memulai - dan tanpa masalah kami mendapatkan sekelompok 4 server S3.
NestJS + Fastify + S3
Saya akan menjelaskan cara bekerja dengan server NestJS dari langkah pertama, meskipun beberapa materi ini dijelaskan dengan sempurna dalam dokumentasi. Instal CLI NestJS:
npm install -g @nestjs/cli
Proyek NestJS baru dibuat:
nest new s3-nestjs-tut
Paket yang diperlukan diinstal (termasuk yang diperlukan untuk bekerja dengan S3):
npm install --save @nestjs/platform-fastify fastify-multipart aws-sdk sharp
npm install --save-dev @types/fastify-multipart @types/aws-sdk @types/sharp
Secara default, proyek menginstal platform NestJS + Express. Cara menginstal Fastify dijelaskan dalam dokumentasi docs.nestjs.com/techniques/performance . Selain itu, kita perlu menginstal plugin untuk menangani Content-Type: multipart / form-data - fastify-multipart
import { NestFactory } from '@nestjs/core';
import {
FastifyAdapter,
NestFastifyApplication,
} from '@nestjs/platform-fastify';
import fastifyMultipart from 'fastify-multipart';
import { AppModule } from './app.module';
async function bootstrap() {
const fastifyAdapter = new FastifyAdapter();
fastifyAdapter.register(fastifyMultipart, {
limits: {
fieldNameSize: 1024, // Max field name size in bytes
fieldSize: 128 * 1024 * 1024 * 1024, // Max field value size in bytes
fields: 10, // Max number of non-file fields
fileSize: 128 * 1024 * 1024 * 1024, // For multipart forms, the max file size
files: 2, // Max number of file fields
headerPairs: 2000, // Max number of header key=>value pairs
},
});
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
fastifyAdapter,
);
await app.listen(3000, '127.0.0.1');
}
bootstrap();
Sekarang kami akan menjelaskan layanan yang mengunggah file ke repositori S3, setelah mengurangi kode untuk menangani beberapa jenis kesalahan (teks lengkap ada di repositori artikel):
import { Injectable, HttpException, BadRequestException } from '@nestjs/common';
import { S3 } from 'aws-sdk';
import fastify = require('fastify');
import { AppResponseDto } from './dto/app.response.dto';
import * as sharp from 'sharp';
@Injectable()
export class AppService {
async uploadFile(req: fastify.FastifyRequest): Promise<any> {
const promises = [];
return new Promise((resolve, reject) => {
const mp = req.multipart(handler, onEnd);
function onEnd(err) {
if (err) {
reject(new HttpException(err, 500));
} else {
Promise.all(promises).then(
data => {
resolve({ result: 'OK' });
},
err => {
reject(new HttpException(err, 500));
},
);
}
}
function handler(field, file, filename, encoding, mimetype: string) {
if (mimetype && mimetype.match(/^image\/(.*)/)) {
const imageType = mimetype.match(/^image\/(.*)/)[1];
const s3Stream = new S3({
accessKeyId: 'minio',
secretAccessKey: 'minio123',
endpoint: 'http://127.0.0.1:9001',
s3ForcePathStyle: true, // needed with minio?
signatureVersion: 'v4',
});
const promise = s3Stream
.upload(
{
Bucket: 'test',
Key: `200x200_${filename}`,
Body: file.pipe(
sharp()
.resize(200, 200)
[imageType](),
),
}
)
.promise();
promises.push(promise);
}
const s3Stream = new S3({
accessKeyId: 'minio',
secretAccessKey: 'minio123',
endpoint: 'http://127.0.0.1:9001',
s3ForcePathStyle: true, // needed with minio?
signatureVersion: 'v4',
});
const promise = s3Stream
.upload({ Bucket: 'test', Key: filename, Body: file })
.promise();
promises.push(promise);
}
});
}
}
Dari fitur-fiturnya, perlu dicatat bahwa kita menulis aliran input menjadi dua aliran output jika gambar dimuat. Salah satu aliran memampatkan gambar menjadi ukuran 200x200. Dalam semua kasus, gaya aliran digunakan. Tetapi untuk menangkap kemungkinan kesalahan dan mengembalikannya ke pengontrol, kita memanggil metode promise (), yang didefinisikan dalam pustaka aws-sdk. Kami mengakumulasi janji yang diterima dalam larik promise:
const promise = s3Stream
.upload({ Bucket: 'test', Key: filename, Body: file })
.promise();
promises.push(promise);
Dan, selanjutnya, kami mengharapkan resolusi mereka dalam metode tersebut
Promise.all(promises).
Kode pengontrol, di mana saya masih harus meneruskan FastifyRequest ke layanan:
import { Controller, Post, Req } from '@nestjs/common';
import { AppService } from './app.service';
import { FastifyRequest } from 'fastify';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Post('/upload')
async uploadFile(@Req() req: FastifyRequest): Promise<any> {
const result = await this.appService.uploadFile(req);
return result;
}
}
Proyek diluncurkan:
npm run start:dev
Repositori artikel github.com/apapacy/s3-nestjs-tut
apapacy@gmail.com
13 Agustus 2020