Node-LokiJS: не все запросы на получение выполнены, статус запроса навсегда ожидает? - PullRequest
1 голос
/ 08 ноября 2019

Я следовал этому руководству при загрузке файлов с помощью multer-express, а затем извлекал изображение по идентификатору Scoth.io .

. В качестве базы данных для установки используется LokiJS.

ВсеAPI работает хорошо, однако, когда API для получения нескольких изображений по идентификатору не работает для нескольких изображений. Большинство запросов на получение ожидают на сервере (статус находится в состоянии ожидания на панели «Сеть» инструментов Chrome Dev).

Запросы никогда не выполняются один раз в состоянии ожидания (навсегда ожидают), и сервер застревает в этом.

Pending-network-requests-chrome-dev-tools

API для получения изображения по идентификатору

app.get('/images/:id', async (req, res) => {
    try {
        const col = await loadCollection(COLLECTION_NAME, db);
        const result = col.get(req.params.id);

        if (!result) {
            res.sendStatus(404);
            return;
        };

        res.setHeader('Content-Type', result.mimetype);
        fs.createReadStream(path.join(UPLOAD_PATH, result.filename)).pipe(res);
    } catch (err) {
        res.sendStatus(400);
    }
})

Index.ts (все API)

import * as express from 'express'
import * as multer from 'multer'
import * as cors from 'cors'
import * as fs from 'fs'
import * as path from 'path'
import * as Loki from 'lokijs'

import { loadCollection, imageFilter } from './utils'

//setup
  const DB_NAME = 'db.json'
  const COLLECTION_NAME = 'images'
  const UPLOAD_PATH = 'uploads'
  const upload = multer({ dest: `${UPLOAD_PATH}/`, fileFilter: imageFilter }) //MULTER CONFIG
  const db = new Loki(`${UPLOAD_PATH}/${DB_NAME}`, { persistenceMethod: 'fs' })

// app  
  const app = express();
  app.use(cors());

  app.get('/', (req, res) => {
    res.json({responseText : 'Server running successfully'})
  })


  //Upload Single
  app.post('/fileUpload', upload.single('file'), async (req, res) => {

    try {
        const col = await loadCollection(COLLECTION_NAME, db)
        const data = col.insert(req.file)

        db.saveDatabase()
        res.send({id: data.$loki, fileName: data.filename, originalName: data.originalname })
      } catch (err) {
        res.sendStatus(400)
      }
  })

//Upload Multiple
 app.post('/photos/upload', upload.array('photos', 12), async (req, res) => {

    try {
        const col = await loadCollection(COLLECTION_NAME, db)
        const data = [].concat(col.insert(req.files))

        db.saveDatabase()
        res.send(data.map(x => ({ id: x.$loki, fileName: x.filename, originalName: x.originalname })));
    } catch (err) {
        res.sendStatus(400)
      }
  })

 //Retrieve Image
 app.get('/images', async (req, res) => {
   try {
       const col = await loadCollection(COLLECTION_NAME, db)
       res.send(col.data)
   } catch(err) {
     res.sendStatus(400)
   }
 })


// Retrieve Image by Id
 app.get('/images/:id', async (req, res) => {
   try {

       const col = await loadCollection(COLLECTION_NAME, db)
       const result = col.get(parseInt(req.params.id))

       if(!result) {
         res.sendStatus(404)
         return;
       }

     res.setHeader('Content-Type', result.mimetype);
     fs.createReadStream(path.join(UPLOAD_PATH, result.filename)).pipe(res)
   } catch(err) {
     res.sendStatus(400)
   }
 })

app.listen(3000, function () {
    console.log('listening on port 3000!');
})

Индекс.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Fetch Image (NodeJS-LokiJS API) - Example</title>
    <style>
      .photo {
        width: 100px;
        display: block;
        margin-bottom: 5px;
        border: 2px solid black;
      }
    </style>    
  </head>
  <body>
    <h1>HTML Example</h1>
    <p>
      JPEG:<br>
      <img class="photo" src="http://localhost:3000/images/1">
      <img class="photo" src="http://localhost:3000/images/2">
      <img class="photo" src="http://localhost:3000/images/3">
      <img class="photo" src="http://localhost:3000/images/4">
      <img class="photo" src="http://localhost:3000/images/5">
      <img class="photo" src="http://localhost:3000/images/6">
    </p>
  </body>
</html>

utils.ts

import * as del from 'del'
import * as Loki from 'lokijs'

const loadCollection = function (colName, db: Loki): Promise<Loki.Collection<any>> {
    return new Promise(resolve => {
    db.loadDatabase({}, _=> {
      const _collection = db.getCollection(colName) || db.addCollection(colName)
      resolve(_collection)
    })
  })
}

const imageFilter = function (req, file, cb) {
    // accept image only
    if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) {
        return cb(new Error('Only image files are allowed!'), false);
    }
    cb(null, true);
}

export { imageFilter, loadCollection }

1 Ответ

1 голос
/ 11 ноября 2019

Похоже, что проблема действительно с loadCollection. Удалите db.loadDatabase из loadCollection и загрузите вашу базу данных только один раз в index.ts после ее инициализации.

index.ts

import * as express from 'express'
import * as multer from 'multer'
import * as cors from 'cors'
import * as fs from 'fs'
import * as path from 'path'
import * as Loki from 'lokijs'

import { loadCollection, imageFilter } from './utils'

//setup
  const DB_NAME = 'db.json'
  const COLLECTION_NAME = 'images'
  const UPLOAD_PATH = 'uploads'
  const upload = multer({ dest: `${UPLOAD_PATH}/`, fileFilter: imageFilter }) //MULTER CONFIG
  const db = new Loki(`${UPLOAD_PATH}/${DB_NAME}`, { persistenceMethod: 'fs' })
  db.loadDatabase({});

// app  
  const app = express();
  app.use(cors());

  app.get('/', (req, res) => {
    res.json({responseText : 'Server running successfully'})
  })


  //Upload Single
  app.post('/fileUpload', upload.single('file'), async (req, res) => {

    try {
        const col = await loadCollection(COLLECTION_NAME, db)
        const data = col.insert(req.file)

        db.saveDatabase()
        res.send({id: data.$loki, fileName: data.filename, originalName: data.originalname })
      } catch (err) {
        res.sendStatus(400)
      }
  })

//Upload Multiple
 app.post('/photos/upload', upload.array('photos', 12), async (req, res) => {

    try {
        const col = await loadCollection(COLLECTION_NAME, db)
        const data = [].concat(col.insert(req.files))

        db.saveDatabase()
        res.send(data.map(x => ({ id: x.$loki, fileName: x.filename, originalName: x.originalname })));
    } catch (err) {
        res.sendStatus(400)
      }
  })

 //Retrieve Image
 app.get('/images', async (req, res) => {
   try {
       const col = await loadCollection(COLLECTION_NAME, db)
       res.send(col.data)
   } catch(err) {
     res.sendStatus(400)
   }
 })


// Retrieve Image by Id
 app.get('/images/:id', async (req, res) => {
   try {

       const col = await loadCollection(COLLECTION_NAME, db)
       const result = col.get(parseInt(req.params.id))

       if(!result) {
         res.sendStatus(404)
         return;
       }

     res.setHeader('Content-Type', result.mimetype);
     fs.createReadStream(path.join(UPLOAD_PATH, result.filename)).pipe(res)
   } catch(err) {
     res.sendStatus(400)
   }
 })

app.listen(3000, function () {
    console.log('listening on port 3000!');
})

utils.ts

import * as del from 'del'
import * as Loki from 'lokijs'

const loadCollection = function (colName, db: Loki): Promise<Loki.Collection<any>> {
    return new Promise(resolve => {
      const _collection = db.getCollection(colName) || db.addCollection(colName)
      resolve(_collection)
  })
}

const imageFilter = function (req, file, cb) {
    // accept image only
    if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) {
        return cb(new Error('Only image files are allowed!'), false);
    }
    cb(null, true);
}

export { imageFilter, loadCollection }
...