Сохранение изображения в серверной части MongoDB с Multer в виде файла из Angular не работает как исключенный

#javascript #angular #mongodb #typescript #blob

#javascript #angular #mongodb #машинописный текст #большой двоичный объект

Вопрос:

Я столкнулся с проблемой, которая, на мой взгляд, не работает. Я установил библиотеку в angular cropper.js https://github.com/matheusdavidson/angular-cropperjs , и во внешнем интерфейсе я имею дело с некоторым кодом, который разработчик разработал для этой библиотеки.

Так что моя итерация будет выглядеть примерно так.

обрезанное изображение будет отправлено в мой api в серверной части, чтобы сохранить файлы и показать файл в каком-либо другом месте.

Фактическая обрезка сохраняет ссылку с большим двоичным объектом, и есть мой img. Запрос post работает, и я вижу, что img находится в папке, но когда я пытаюсь получить изображение, get it работает, но в консоли интерфейса мне это говорит. GET http://localhost:4200/images/image-1607708300007.jpg 404 (Not Found)

Но в GET запросе это изображение есть.

 {"_id":"5fd3bf6f946e9c40163d82f3",
 "imageTitle":"undefined",
 "imageDesc":"undefined",
 "imageUrl":"/images/image-1607712623266.jpg",
 "uploaded":"2020-12-11T18:50:23.288Z","__v":0}
 

Но если я попытаюсь с помощью postman получить это, это не сработает.
Я стараюсь в почтальоне вот так.
http://localhost:4200/images/image-1607713934301.jpg это то же сообщение об ошибке, что и в консоли.

 `<pre>Cannot GET /images/image-1607713934301.jpg</pre>`
 

Если я попытаюсь записать, что интерфейс отправляет на серверную часть, у меня получится что-то вроде.
console.log(req.file);

    { fieldname: 'file',
  originalname: 'acf6a796-7b4b-4b12-b429-1d21352f3a45.jpeg',
  encoding: '7bit',
  mimetype: 'image/jpeg',
  destination: '/Users/abedinzhuniqi/Projects/xxxx/images',
  filename: 'image-1607712623266.jpg',
  path:
   '/Users/abedinzhuniqi/Projects/xxxx/images/image-1607712623266.jpg',
  size: 1540633 }
 

Это мой внешний интерфейс.
Это и есть html-код.

 <angular-cropper #angularCropper
[cropperOptions]="imgConfig"
 [imageUrl]="imgUrl | safeurl"></angular-cropper>
 <div class="btn-group">
      <label class="btn btn-primary btn-upload" for="inputImage" title="Upload image file" >
        <input type="file" class="sr-only" id="inputImage" name="file" accept="image/*" (change)="fileChangeEvent($event)">
        <span class="docs-tooltip" data-toggle="tooltip" title="" data-original-title="Import image with Blob URLs">
          <span class="fa fa-upload"></span>
        </span>
      </label>
    </div>
<button type="button" class="btn btn-primary" data-method="crop" title="Crop" (click)="saveImage()">
        <span class="docs-tooltip" data-toggle="tooltip" title="" data-original-title="cropper.crop()">
          <span class="fa fa-check"></span>
        </span>
      </button>
 

А это мой ТС.

   imgUrl = "";
  image: Image;
  imageURL;


   imgConfig = {
    aspectRatio : 3/4,
    dragMode : "move",
    background : true,
    movable: true,
    rotatable : true,
    scalable: true,
    zoomable: true,
    viewMode: 1,
    checkImageOrigin : true,
    checkCrossOrigin: true
};

  fileChangeEvent(event: any): void {
  this.imgUrl = URL.createObjectURL(event.target.files[0]);
  this.image = event.target.files[0];
  }
saveImage() {
  console.log(this.image);
   const file = new File([this.imgUrl], this.image.type);
  this.imageService.addImage(this.image, file).subscribe((res: any) => {
    if (res.body) {
     this.imageService.getImageByID(res.body._id).subscribe((t: Image) => {
     this.imageURL = t.imageUrl;
     });
    }
  }, (err: any) => {
    console.log(err);
  });
}
 

This is the Service

 export class ImageService {
   apiUrl = environment.backend;

  constructor(private http: HttpClient) { }


  addImage(image: Image, file: File): Observable<any> {
    const formData = new FormData();
    formData.append("file", file);
    formData.append("imageTitle", image.imageTitle);
    formData.append("imageDesc", image.imageDesc);
    const header = new HttpHeaders();
    const params = new HttpParams();

    const options = {
      params,
      reportProgress: true,
      headers: header
    };
    const req = new HttpRequest("POST", this.apiUrl, formData, options);
    return this.http.request(req);
  }
  getImageByID(id: string): Observable<any> {
    const url = `${this.apiUrl}/${id}`;
    return this.http.get<Image>(url).pipe(
      catchError(this.handleError)
    );
  }
  private handleError(error: HttpErrorResponse): any {
    if (error.error instanceof ErrorEvent) {
      console.error('An error occurred:', error.error.message);
    } else {
      console.error(
        `Backend returned code ${error.status}, `  
        `body was: ${error.error}`);
    }
    return throwError(
      'Something bad happened; please try again later.');
  }

}
 

И мой серверный API выглядит следующим образом.

     const multer  = require('multer');
    const Image = require("../models/image");


    const storage = multer.diskStorage({
    destination: (req, file, cb) => {
      console.log(cb);
      cb(null, path.join(__dirname, '../../../../images'));
    },
    filename: (req, file, cb) => {
      var filetype = '';
      if(file.mimetype === 'image/gif') {
        filetype = 'gif';
      }
      if(file.mimetype === 'image/png') {
        filetype = 'png';
      }
      if(file.mimetype === 'image/jpeg') {
        filetype = 'jpg';
      }
      cb(null, 'image-'   Date.now()   '.'   filetype);
    }
});

const upload = multer({storage: storage});
routes.get('/:id', function(req, res, next) {
    Image.findById(req.params.id, function (err, gallery) {
        if (err) return next(err);
        res.json(gallery);
    });
});
  
// post data
routes.post('/', upload.single('file'), function(req, res, next) {
    if(!req.file) {
        return res.status(500).send({ message: 'Upload fail'});
    } else {
        req.body.imageUrl = req.file.filename;
        Image.create(req.body, function (err, image) {
            if (err) {
                console.log(err);
                return next(err);
            }
            res.json(image);
        });
    }
});
 

Комментарии:

1. Возможно, вы используете URL.createObjectURL() при получении обрезанного изображения. Вместо этого вам нужно изображение в формате blob для загрузки на сервер. Вы можете использовать toDataUrl() функцию для получения большого двоичного объекта.

2. @AliWahab как это возможно?

3. Что вы используете для обрезки вашего изображения?

4. Я использую эту библиотеку, см. Ссылку на github.

5. Можете ли вы подтвердить, что ваш API работает на postman?

Ответ №1:

Ваш сервер должен отправить содержимое изображения. В настоящее время вы отвечаете только JSON, который содержит путь к изображению, но не само изображение. Для этого вам необходимо добавить промежуточное ПО статического файла:

 app.use('/images', express.static(path.join(process.cwd(), '../images'))
 

Затем вы должны заставить свой хост выдавать правильные URL-адреса, которые вам понадобятся для обновления объекта, который вы возвращаете с сервера, следующим образом:

 routes.get('/:id', function(req, res, next) {
    Image.findById(req.params.id, function (err, gallery) {
        if (err) return next(err);
        res.json({
            ...gallery.toJSON(),
            imageUrl: `//${req.host}:${req.port}/${gallery.imageUrl}`,
        });
    });
});
 

Таким образом, вы будете обслуживать статический контент и получать правильные URL-адреса на стороне интерфейса.

Комментарии:

1. @PaulRumnik как отправить содержимое?

2. У меня такая же ошибка в HTML. http://localhost:4200/images/image-1607871519730.png 404 (Not Found)

3. @Abedin. Zhuniqi express.static сделает это за вас. Вам нужно только убедиться, что а) изображения попадают в папку images (с помощью файлового менеджера) б) запросы к изображению (например /images/picture.png ) проходят хорошо (с помощью браузера).

4. Нужно ли мне добавлять папку в серверную папку или я могу сделать это снаружи? Я попробовал, но он выдает мне ту же ошибку в angular. Я не понял, что вы имели в виду под файловым менеджером?

5. Я имею в виду, что вы должны загрузить файл с созданным вами кодом, а затем убедиться, что загрузка работает, и файл попадает в папку назначения на сервере. Чтобы убедиться, что вы можете открыть файловый менеджер и проверить, есть ли новый файл в /Users/abedinzhuniqi/Projects/xxxx/images/ папке images. Если это так, то express.static должен решить проблему. Если файла нет, то проблема в другой части вашего кода.