sql >> データベース >  >> NoSQL >> MongoDB

RESTAPIから返された画像は常に壊れて表示されます

    base64でエンコードされた画像を返送しないでください(複数の画像+大きなファイル+大きなエンコードされた文字列=パフォーマンスが非常に遅い)。画像のアップロードとその他の画像関連のget/post / put/deleteリクエストのみを処理するマイクロサービスを作成することを強くお勧めします。メインアプリケーションから分離します。

    例:

    • 画像バッファを作成するためにmulterを使用しています
    • 次に、sharpまたはfsを使用して画像を保存します(ファイルタイプによって異なります)
    • 次に、ファイルパスをコントローラーに送信してDBに保存します
    • 次に、フロントエンドはアクセスを試みるときにGETリクエストを実行します:http://localhost:4000/uploads/timestamp-randomstring-originalname.fileext

    簡単に言うと、私のマイクロサービスは画像専用のCDNのように機能します。

    たとえば、ユーザーが投稿リクエストをhttp://localhost:4000/api/avatar/createに送信します。 いくつかのFormDataを使用:

    最初にいくつかのExpressミドルウェアを通過します:

    libs / Middleware.js

    ...
    app.use(cors({credentials: true, origin: "http://localhost:3000" })) // allows receiving of cookies from front-end
    
    app.use(morgan(`tiny`)); // logging framework
    
    app.use(multer({
            limits: {
                fileSize: 10240000,
                files: 1,
                fields: 1
            },
            fileFilter: (req, file, next) => {
                if (!/\.(jpe?g|png|gif|bmp)$/i.test(file.originalname)) {
                    req.err = `That file extension is not accepted!`
                    next(null, false)
                }
                next(null, true);
            }
        }).single(`file`))
    
    app.use(bodyParser.json()); // parses header requests (req.body)
    
    app.use(bodyParser.urlencoded({ limit: `10mb`, extended: true })); // allows objects and arrays to be URL-encoded
    
    ...etc     
    

    次に、avatarsをヒットします ルート:

    routers / avatars.js

    app.post(`/api/avatar/create`, requireAuth, saveImage, create);
    

    次に、ユーザー認証を通過してから、saveImageを通過します。 ミドルウェア:

    services / saveImage.js

    const createRandomString = require('../shared/helpers');
    const fs = require("fs");
    const sharp = require("sharp");
    const randomString = createRandomString();
    
    if (req.err || !req.file) {
      return res.status(500).json({ err: req.err || `Unable to locate the requested file to be saved` })
      next();
    }
    
    const filename = `${Date.now()}-${randomString}-${req.file.originalname}`;
    const filepath = `uploads/${filename}`;
    
    const setFilePath = () => { req.file.path = filepath; return next();}
    
    (/\.(gif|bmp)$/i.test(req.file.originalname))
        ? fs.writeFile(filepath, req.file.buffer, (err) => {
                if (err) { 
                  return res.status(500).json({ err: `There was a problem saving the image.`}); 
                  next();
                }
    
                setFilePath();
            })
        : sharp(req.file.buffer).resize(256, 256).max().withoutEnlargement().toFile(filepath).then(() => setFilePath())
    

    ファイルが保存されると、req.file.pathが送信されます。 私のcreateに コントローラ。これは、ファイルパスおよび画像パス(avatarFilePath)としてDBに保存されます。 または/uploads/imagefile.ext 削除の目的で保存され、avatarURL または[http://localhost:4000]/uploads/imagefile.ext 保存され、フロントエンドのGETリクエストに使用されます):

    controllers / avatars.js (私はPostgresを使用していますが、Mongoの代わりに使用できます)

    create: async (req, res, done) => {
                try {
                    const avatarurl = `${apiURL}/${req.file.path}`;
    
                    await db.result("INSERT INTO avatars(userid, avatarURL, avatarFilePath) VALUES ($1, $2, $3)", [req.session.id, avatarurl, req.file.path]);
    
                    res.status(201).json({ avatarurl });
                } catch (err) { return res.status(500).json({ err: err.toString() }); done(); 
            }
    

    次に、フロントエンドがuploadsにアクセスしようとしたとき <img src={avatarURL} alt="image" />経由のフォルダ または<img src="[http://localhost:4000]/uploads/imagefile.ext" alt="image" /> 、マイクロサービスによって提供されます:

    libs / server.js

    const express = require("express");
    const path = app.get("path");
    const PORT = 4000;
    
    //============================================================//
    // EXPRESS SERVE AVATAR IMAGES
    //============================================================//
    app.use(`/uploads`, express.static(`uploads`));
    
    //============================================================//
    /* CREATE EXPRESS SERVER */
    //============================================================//
    app.listen(PORT);
    

    リクエストをログに記録するときの外観:

    19:17:54 INSERT INTO avatars(userid, avatarURL, avatarFilePath) VALUES ('08861626-b6d0-11e8-9047-672b670fe126', 'http://localhost:4000/uploads/1536891474536-k9c7OdimjEWYXbjTIs9J4S3lh2ldrzV8-android.png', 'uploads/1536891474536-k9c7OdimjEWYXbjTIs9J4S3lh2ldrzV8-android.png')
    
    POST /api/avatar/create 201 109 - 61.614 ms
    
    GET /uploads/1536891474536-k9c7OdimjEWYXbjTIs9J4S3lh2ldrzV8-android.png 200 3027 - 3.877 ms
    

    GETリクエストが成功したときにユーザーに表示される内容:




    1. ある種の行番号をmongodbaggregateコマンド/パイプラインに追加します

    2. エラー:updateOneを実行する場合、更新操作ドキュメントにはアトミック演算子が含まれている必要があります

    3. WebfactionでのRedisの設定

    4. IPアドレスをmongoDBに保存します