sql >> Databasteknik >  >> NoSQL >> MongoDB

Bild som returneras från REST API visas alltid trasig

Undvik att skicka tillbaka base64-kodade bilder (flera bilder + stora filer + stora kodade strängar =mycket långsam prestanda). Jag rekommenderar starkt att du skapar en mikrotjänst som bara hanterar bilduppladdningar och andra bildrelaterade förfrågningar om att hämta/lägga upp/lägga/ta bort. Separera den från din huvudapplikation.

Till exempel:

  • Jag använder multer för att skapa en bildbuffert
  • Använd sedan skarp eller fs för att spara bilden (beroende på filtyp)
  • Då skickar jag sökvägen till min styrenhet för att sparas i min DB
  • Sedan gör gränssnittet en GET-begäran när det försöker komma åt:http://localhost:4000/uploads/timestamp-randomstring-originalname.fileext

I enkla termer fungerar min mikrotjänst som ett CDN enbart för bilder.

Till exempel skickar en användare en inläggsbegäran till http://localhost:4000/api/avatar/create med vissa FormData:

Den passerar först genom några Express-mellanprogram:

libs/middlewares.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     

Tryck sedan på avatars rutt:

routes/avatars.js

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

Den går sedan igenom viss användarautentisering och går sedan igenom min saveImage mellanprogram:

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())

Om filen sparas skickar den en req.file.path till min create kontroller. Detta sparas i min DB som en filsökväg och som en bildsökväg (avatarFilePath eller /uploads/imagefile.ext sparas för borttagningsändamål och avatarURL eller [http://localhost:4000]/uploads/imagefile.ext sparas och används för front-end GET-begäran):

controllers/avatars.js (Jag använder Postgres, men du kan ersätta 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(); 
        }

Sedan när gränssnittet försöker komma åt uploads mapp via <img src={avatarURL} alt="image" /> eller <img src="[http://localhost:4000]/uploads/imagefile.ext" alt="image" /> , den serveras av mikrotjänsten:

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

Så här ser det ut när du loggar förfrågningar:

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

Vad användaren ser efter en lyckad GET-förfrågan:




  1. Rails 3:hur man använder aktiv skiva och mongoid samtidigt

  2. mongoose skillnaden mellan findOneAndUpdate och uppdatering

  3. Är MongoDB på något sätt begränsad till en enda kärna?

  4. Använder PouchDB med MongoDB