【问题标题】:I'm trying to display images that I uploaded to my backend with multer我正在尝试使用 multer 显示我上传到后端的图像
【发布时间】:2019-04-20 01:36:26
【问题描述】:

我正在使用 multer 从我的 react 客户端上传图片。所有的图像都被存储了,只是没有显示出来。图像正在被存储,但没有出现在反应中。设置在状态只是不显示。我可以在后端的图像文件夹中看到它们,所以我知道 multer 正在工作。

这是我的反应组件

class AddNewDish extends Component {
    constructor(props){
        super(props)
        this.state = {
            name: '',
            imageUrl: '',
            description: ''

        }
    }



    createDishHandler = (event) => {
        event.preventDefault()
        const fd = new FormData();
        fd.append('name', this.state.name)
        fd.append('imageUrl', this.state.imageUrl, this.state.imageUrl.name)
        fd.append('description', this.state.description)
        axios.post('http://localhost:8080/add-new-dish', fd,)
            .then(res => {
                console.log(res, 'res')
            })
        this.props.history.push('/')
    }


    onChange = (e) => {
        switch(e.target.name) {

            case 'imageUrl':
                this.setState({imageUrl: e.target.files[0]});
                break;
            default:
                this.setState({[e.target.name]: e.target.value})
        }
        console.log(e)
    }



    render () {
        console.log(this.state.imageUrl, 'in imgUrl')
        return (
            <div>
             <form onSubmit={this.createDishHandler}> 
                <input
                    label='Name'
                    onChange={this.onChange}
                    name='name'
                    type='text'
                    placeholder='Enter Dish Name'
                    value={this.state.name}
                />

                < input
                    label='Dish Image'
                    onChange={this.onChange}
                    name='imageUrl'
                    type='file'
                    placeholder='Enter Dish Image'
                    // value={this.state.imageUrl}
                />

                 <input
                    label='Description'
                    onChange={this.onChange}
                    name='description'
                    placeholder='Enter Dish Description'
                    type='text'
                    value={this.state.description}
                />
                <img src={this.state.imageUrl}/>
                 <button>Submit Dish</button> 
             </form> 
            </div>
        )
    }
};

export default AddNewDish

一个后端


const multer = require('multer');

const fileStorage = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, 'public')
    },
    filename: (req, file, cb) => {
        cb(null, new Date().toISOString() + '-' + path.extname(file.originalname))
    }
});

const fileFilter = (req, file, cb) => {
    if(
        file.mimetype === 'image/png' ||
        file.mimetype === 'image/jpg' || 
        file.mimetype === 'image/jpeg'
        ) {
            cb(null, true)
    } else {
        cd(null, false)
    }
}
exports.upload = multer({

        storage: fileStorage, 
        fileFilter: fileFilter
    })
        .single('imageUrl')

这就是我如何称呼我的路线

exports.postADish = async  ( req, res,) => {
    console.log(req.file, 'in req.file')

    try {
        const { name,  description } = req.body;
        const imageUrl = req.file.path

            const newDish = await dish.postNewDish({name, description, imageUrl})
            res.status(201).json(`new dish added`)

    } catch (err) {
        res.status(500).json(`Error posting dish`)
        console.log(err)
    }
};

我如何使用上传中间件

router.post('/add-new-dish', dishController.upload, dishController.postADish);

公开文件夹

app.use('/public', express.static('public'))

这就是我尝试在前端的索引路由中显示图像的方式

class App extends Component {
  constructor () {
    super()
    this.state = {
      data: []

    }

  }

    componentDidMount()  {
      axios
        .get(`http://localhost:8080/`)
        .then(res => {
          console.log(res, 'response')
          this.setState({
            data: res.data.dishData
          })
        })
        .catch(err => {
          console.log(err)
        })
  }


  render() {
   console.log(this.state.data)
    return (
      <div className="App">
        <Nav

         <Route
            exact path ='/'
            render={props =>
              <Home 
                {...props}
                dishes={this.state.data}

              />
            }
          />

我的状态是这样的

{id: 7, name: "test dish", imageUrl: "public/2019-04-20T22:52:09.900Z-20190411_112505.jpg", description: "test description"}

我正在取回 imageUrl 并像这样在 home 组件中使用它

const Home = (props) => {
    return (
        <DishWrapper>
            <DishContent>
           {props.dishes.map(dish => {
               console.log(dish, 'in dish')
               return (

                   <Dish key={dish.id}>
                        <h3>{dish.name}</h3>
                        <img src={ `public/${dish.imageUrl}`} alt={dish.name}/>
                        <h5>{dish.description}</h5>
                   </Dish>

               )
           })}
            </DishContent>
        </DishWrapper>
    )
};

export default Home

在后端我的 get 看起来像这样

exports.getDishes = async (req, res) => {
    try {
        const dishData = await dish.getDishes()
        if(!dishData) {
            res.status(404).json(`No dishes available at this time`)
        } else {
            res.status(200).json({
                dishData, 

            })
        }
    } catch (err) {
        res.status(500)
        console.log(err)
    }
};

【问题讨论】:

  • 在我看来,您在 axios 调用中将一个 imageUrl 从您的组件发送到 multer,然后在上传之前将日期字符串添加到文件名中,对吗?如果是这样,您需要在 res 中返回该文件名并将其用作图像 src。当您在路由中控制台记录 req.file 时会得到什么,您是否获得更新的文件名?
  • 这是我在 req.file 控制台日志{ fieldname: 'imageUrl', originalname: '20190411_112542.jpg', encoding: '7bit', mimetype: 'image/jpeg', destination: 'images', filename: '2019-04-20T01:00:07.965Z-.jpg', path: 'images/2019-04-20T01:00:07.965Z-.jpg', size: 2361225 } 中得到的内容@
  • 所以在我的 .json 中我应该发送 imageUrl?
  • 所以我只是注意到上传图片后您将页面更改为索引。您是否在单击提交按钮之前或之后查看图像时遇到问题?如果它在你之前,你需要采取不同的方法,如果它在之后,那么你需要将图像文件名发送回你的 res.
  • 我在查看之前和之后的图像时都遇到了问题

标签: mysql node.js reactjs multer


【解决方案1】:

因此,要在上传之前查看图像,您需要首先使用FileReader,这是一个允许 Web 应用程序异步读取文件内容的 javascript 对象。这将为您提供一个 base64 版本的图像,您可以将其添加到图像 src。因此,您可以在 onChange 函数中执行此操作,它看起来类似于以下内容:

onChange = (e) => {
    switch(e.target.name) {

        case 'imageUrl':
            const file = e.target.files[0];
            const reader = new FileReader();
            reader.onload = () => {
                this.setState({
                    imageUrl: file,
                    imgBase64: reader.result
                })
            };
            reader.readAsDataURL(file);
            break;
        default:
            this.setState({[e.target.name]: e.target.value})
    }
}

在本例中,我将imgBase64 键添加到状态,并将base64 值添加到其中,但您可以使用任何您喜欢的名称,只要确保将其添加到您的状态对象即可。

然后要查看它,您可以使用这个值作为图像 src,如下所示:

<img src={this.state.imgBase64}/>

之后,当您将图像提交给 multer 时,您需要返回图像的文件名,以便在上传后可以访问它到您的 axios 调用并在此之后使用它。因此,在您的路线中,只需发回一个 json 对象并使用它。所以不是res.status(201).json(new disc added) 而是发送如下内容:

res.status(201).json({
  msg: 'new dish added',
  imageUrl: req.file.filename
})

然后您的 axios 调用将收到此 json 对象,之后您可以在前端访问,如下所示:

createDishHandler = (event) => {
    event.preventDefault()
    const fd = new FormData();
    fd.append('name', this.state.name)
    fd.append('imageUrl', this.state.imageUrl, this.state.imageUrl.name)
    fd.append('description', this.state.description)
    axios.post('http://localhost:8080/add-new-dish', fd,)
        .then(res => {
            //you can set your res.data.imageUrl to your state here to use it
            console.log('Success Message: ' + res.data.msg + ' - Image File Name: ' + res.data.imageUrl)
        })
    this.props.history.push('/')
}

但在上述功能中,我看到您在上传时推送了不同的页面。因此,如果您推送到不同的页面,那么您显然不会再使用此状态,因此您可能需要从新页面的那个点从您的数据库中检索它。

无论如何,我希望这会有所帮助,如果您有任何问题,请告诉我。

附:我只是想让您知道,您可能想在 multer 上传中使用 Date.now() + path.extname(file.originalname) 而不是 new Date().toISOString() + '-' + path.extname(file.originalname),它看起来更简洁,没有所有的冒号和破折号,但没有必要。

编辑:

因此,如果您要使用 express 提供静态文件夹,那么就像我在下面之前的 cmets 中所说的那样,您将不得不使用绝对 url 来访问您的内容。 React 无法访问客户端公共文件夹之外的相对路径的任何内容。因此,如果在您的后端根目录中,您将有一个名为 images 的文件夹,那么在 multer 中,您将使用 express 将目标设置为 'images',您将提供静态文件夹 app.use(express.static('images')) 并使用您的图像访问它,您需要使用绝对网址

<img src={ `http://localhost:8080/${imageUrl}`} alt={dish.name}/>

【讨论】:

  • 感谢您的帮助。图像现在正在显示,但未发送回后端。我得到一个 ``` Cannot read property 'path' of undefined ``` 。它在邮递员中运行良好,但在前端却不行。我console log (fd) (formDate)它返回一个空对象。不知道是不是这个问题。
  • 这可能是因为我在 onchange 函数期间忘记将图像文件设置为您状态下的 imageUrl,因为您将其作为文件传递给表单数据,抱歉,有很多事情要做。我编辑了答案以包含它。试试看会发生什么
  • 我正在尝试在主页中显示图像,但没有显示。我删除了推送。它会在错误的位置。对不起,如果我打扰你,我以前从未处理过文件上传。我编辑了我的可能以包括前端和后端获取请求。
  • 你上传图片的文件夹在哪里?它应该在公共文件夹中。如果您将它放在其他任何地方,您将无法访问它,因为如果您无法通过 url 访问应用程序中的其他任何地方。因此,如果您的图像文件位于公共文件夹中,则图像应如下所示 &lt;img src="/images/yourimage.jpg"/&gt; 但从外观上看,您只是上传到与您的 multer 脚本位于同一目录中的图像文件夹。
  • 图片折叠在后端的根目录,而不是在公共文件夹。我认为通过将图像文件夹设为静态,我就可以访问它了?
猜你喜欢
  • 2017-12-22
  • 1970-01-01
  • 2019-12-07
  • 2018-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-25
  • 1970-01-01
相关资源
最近更新 更多