【问题标题】:How to store photo fast in React with API nodeJS如何使用 API nodeJS 在 React 中快速存储照片
【发布时间】:2020-01-14 04:18:21
【问题描述】:

在将图像发送到 NodeJS 服务器之前,我将它们转换为 base64 字符串。 然后,我将 base64 字符串存储到 MongoDB 中。 问题是当我尝试从数据库中获取 base64 字符串时,需要很长时间(10 张图像大约需要 1 分钟)。 我的网站处理大量图片。

这是我的 React 代码:

import React, { Component, useState, useCallback } from "react"
import Header from '../Header'
import ModalCountry from '../ModalCountry'
import Photo from './Photo'
import Gallerie from './Gallerie';
import ReactFileReader from 'react-file-reader'
import Config from '../../Config'
import './styles.css'

class Photos extends Component {
    constructor(props){
        super(props)

        this.state = {
            countryAlpha3: this.props.location.state ? this.props.location.state.lookedAlpha3 : "",
            photos: [],
            showAddPhotos: "d-none",
            photosToAdd: []
        }

        this.handleFiles = this.handleFiles.bind(this);
        this.storePhotos = this.storePhotos.bind(this);
    }

    handleFiles(files){
        let photosStamp = [];
        files.base64.forEach(function(file){
            photosStamp.push({
                photo: file,
                base64: file,
                title: "Titre",
                description: "Description"
            })
        })
        this.setState({
            photosToAdd: photosStamp
        }, () => console.log(this.state.photosToAdd))

        this.setState({
            showAddPhotos: 'd-block'
        })
    }

    componentDidMount(){
        var photosArray = this.state.photos;
        let self = this;
        fetch(Config.apiUrl + 'photos_thisUser/' + this.state.countryAlpha3, {
            method: 'GET',
            credentials: 'include',
            headers: {
              'Content-Type': 'application/json',
              "Authorization": localStorage.getItem("xsrfToken")
            }
          })
          .then(response => response.json())
          .then(body => {
              body.forEach(function(data){
                  self.setState({
                      photos: self.state.photos.concat({
                          photo: data.base64,
                          caption: data.title,
                          subcaption: data.description
                      })
                  })
              })
          })
          .catch(err => {
              console.log(err)
          })
    }

    storePhotos(){
        fetch(Config.apiUrl + 'addPhotos', {
            method: 'PUT',
            credentials: 'include',
            body: JSON.stringify({
              'photos': this.state.photosToAdd,
              'alpha3': this.state.countryAlpha3
            }),
            headers: {
              'Content-Type': 'application/json',
              "Authorization": localStorage.getItem("xsrfToken")
            }
          })
          .then(response => response.json())
          .then(body => {
            this.setState({
                photos: this.state.photos.concat(this.state.photosToAdd),
                showAddPhotos: "d-none",
                photosToAdd: []
            })
          })
          .catch(err => {
              console.log(err)
          })
    }


    render() {   

        return (
            <div className="mainPhotos">
                {this.state.redirection}
                <div className="profileHeader">
                    <Header openModal={this.getDataFromSearchBar} />
                </div>
                <ModalCountry ref={this._child} modalTitle={this.state.modalTitle} alpha3={this.state.alpha3} />
                <div className="header">
                    <div className="banner col-md-12 row">               
                        <div className="col-md-12 titlePhotos text-center">
                            Photos de {this.state.countryName}
                        </div>
                    </div>
                </div>
            <div className="photosContent">               
                <div className="text-center">
                    <ReactFileReader fileTypes={[".png", ".jpg", ".jpeg", ".bmp"]} base64={true} multipleFiles={true} handleFiles={this.handleFiles}>
                        <button className="btn btn-info">Ajouter des photos</button>
                    </ReactFileReader>
                </div>

                <div className={"photosToAdd row text-center " + (this.state.showAddPhotos)}>
                    <div className="photosFull photosToAddWithButton">
                        {this.state.photosToAdd.map((item, index) => <Photo src={item.photo} openLightbox={() => {console.log("opened")}} />)}
                    </div>
                    <div className="col-md-12 text-center">
                        <button
                            className="btn btn-success form-control btnValid col-md-1"
                            onClick={this.storePhotos}
                        >
                            Ajouter
                        </button>
                        <button
                            className="btn btn-danger form-control btnCancel col-md-1"
                            onClick={this.cancelAddPhotos}
                        >
                            Annuler
                        </button>
                    </div>
                </div>           

                <div className="photosContent row">
                    <div className="photosFull">
                        {this.state.photos.map((item, index) => <Photo src={item.photo} openLightbox={() => {this.setState({
                            activePhotoIndex: index
                        }, this.setState({
                            galleryIsVisible: true
                        }))}} />)}
                        <Gallerie photos={this.state.photos} activePhotoIndex={this.state.activePhotoIndex} galleryIsVisible={this.state.galleryIsVisible} close={() => this.setState({
                            galleryIsVisible: false
                        })} />
                    </div>
                </div>
            </div>
            </div>
        )
    }
}

export default Photos

这是我的 nodeJS 代码:

var express = require('express')
var router = express.Router()
const Photo = require('../../models/Photo')
const Country = require('../../models/Country')
let mongoose = require('mongoose')

router.put('/addPhotos', function(req, res, next){
    if(req.body.alpha3 && req.body.photos){
        Country.findOne({ alpha3: req.body.alpha3 })
        .then(country => {
            console.log(req.body.photos)
            req.body.photos.forEach(function(photo){
                photoToAdd = new Photo({
                    country: mongoose.Types.ObjectId(country._id),
                    user: mongoose.Types.ObjectId(req.decoded.id),
                    base64: photo.base64,
                    title: photo.title,
                    description: photo.description
                });
                photoToAdd.save(function(err, addedPhoto){
                })
            })
            {
                res.json({
                    success: true,
                    message: "Photos added"
                })
            }
        })
    }
    else
    {
        res.json({
            error: req.body.alpha3
        })
    }
})


router.get('/photos_thisUser/:alpha3', function(req, res, next){
        Country.findOne({ alpha3: req.params.alpha3 })
        .then(country => {
            Photo.find({ user: req.decoded.id, country: country._id }, {_id: 0, country: 0})
            .then(photos => {
                res.json(photos)
            })
            .catch(err => {
                res.status(400).send({
                    success: false,
                    message: "Error: " + err
                })
            })
        })
        .catch(err => {
            res.status(400).send({
                success: false,
                message: "Error: " + err
            })
        })
})

module.exports = router

这是猫鼬模式:

let mongoose = require('mongoose');

const PhotoSchema = new mongoose.Schema({
    country: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Country'
    },
    user: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User'
    },
    base64: {
        type: String,
        required: true
    },
    title: {
        type: String
    },
    description: {
        type: String
    }
});

let PhotoModel = mongoose.model('Photo', PhotoSchema);

module.exports = PhotoModel

也许我不应该将 base64 数据存储到 mongo 中的字符串中? 我想一张一张地显示图片,这样用户就不用等太久了。 但是我怎样才能只更新状态的一部分呢? 还是在我的网站中使用 base64 是错误的技术?

【问题讨论】:

  • 我认为与其将 base64 存储在数据库中,不如将图像存储到应用程序文件夹中,然后将文件路径保存在 MongoDB 集合中。您可以在应用程序文件夹中使用单独的文件夹来存储图像。

标签: node.js reactjs image base64


【解决方案1】:

将您的图像存储为 base64 编码字符串不是一个好主意,因为它们将是 approximately 37% larger 而不是其原始二进制表示。
如果您的网站是基于图片的,您应该将图片保存在某处。
作为本地解决方案,您可以将它们存储在您的服务器中,然后将图像路径保存在您的数据库中,否则您可以使用云解决方案,例如 AWS S3,然后使用它们的 api 存储和检索图像。
如果您的网站有很多图像和访问量,尽管它们不是免费的,我建议使用一些云解决方案,因为它们(几乎)开箱即用,具有一些很酷的功能,如缓存和图像处理,您不必照顾磁盘空间或服务器性能。检索(可能缓存的)缩放图像,总是比 base64 编码或保存在服务器上的全尺寸图像快。关于前端,您可以使用一些反应延迟加载模块在需要时加载和显示您的图片。

【讨论】:

  • 好的,谢谢您的帮助。所以我可以使用云服务器来存储我的图像或将它们存储到我的 react 应用程序的文件夹中,然后将路径存储到 mongoDB 中。但正如我所想,base64 不应该在这里使用,因为它给出的性能很差。非常感谢您的建议!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-07
  • 2016-12-06
  • 1970-01-01
  • 1970-01-01
  • 2021-12-26
  • 1970-01-01
  • 2011-09-30
相关资源
最近更新 更多