React 和 Node 应用程序未将图像上传到 Cloudinary,404 错误没有解释

Posted

技术标签:

【中文标题】React 和 Node 应用程序未将图像上传到 Cloudinary,404 错误没有解释【英文标题】:React and Node application not uploading Images to Cloudinary, 404 error with no explanation 【发布时间】:2021-03-23 09:37:14 【问题描述】:

我正在尝试将图像上传到 cloudinary。我正在使用这个资源作为我的教程...

我能够在我的屏幕上呈现图像的预览,并在控制台记录 base64 编码的 url,它可以正常工作。选择我的图像后,我点击上传,我的 POST 请求出现 404 错误,但没有关于它发生原因的信息。我的开发控制台的网络标签下没有BAD REQUEST。我的 Cloudinary 从未渲染过任何图像。

开始,这是我的 index.js 代码

const connectDB = require('./startup/db');
const express = require('express');
const app = express();
const users = require('./routes/users');
const kittys = require('./routes/kittys');
const friends = require('./routes/friends');
const image = require('./routes/image');
const auth = require('./routes/auth')
const cors = require("cors");
const bodyParser = require('body-parser');
const path = require('path');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const  cloudinary  = require('./utils/cloudinary');
// const createError = require('http-errors');

connectDB();

app.use(cors());
app.use(express.json());
app.use('/api/users', users);
app.use('/api/kittys', kittys);
app.use('/api/auth', auth);
app.use('/api/friends', friends);
app.use('api/upload', image)


app.use((req, res, next) => 
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
    res.header('Access-Control-Allow-Credentials', true);
    res.header('Access-Control-Allow-Methods', '*');  // enables all the methods to take place
    return next();
  );


app.use(logger('dev'));
app.use('/uploads', express.static('uploads'));
app.use(bodyParser.json(limit: '50mb'));
app.use(bodyParser.urlencoded(limit: '50mb', extended: true));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));


app.get('/*',(req,res)=>
  res.sendfile(path.join(__dirname='/public'));
)


const port = process.env.PORT || 5000;
app.listen(port, () => 
    console.log(`Server started on port: $port`);
)

这是我的 image.jsx(component) 代码

import React,  useState  from 'react';
import Alert from './Alert.js'

export default function Upload() 
    const [fileInputState, setFileInputState] = useState('');
    const [previewSource, setPreviewSource] = useState('');
    const [selectedFile, setSelectedFile] = useState();
    const [successMsg, setSuccessMsg] = useState('');
    const [errMsg, setErrMsg] = useState('');
    const handleFileInputChange = (e) => 
        const file = e.target.files[0];
        previewFile(file);
        setSelectedFile(file);
        setFileInputState(e.target.value);
    ;

    const previewFile = (file) => 
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onloadend = () => 
            setPreviewSource(reader.result);
        ;
    ;

    const handleSubmitFile = (e) => 
        e.preventDefault();
        if (!selectedFile) return;
        const reader = new FileReader();
        reader.readAsDataURL(selectedFile);
        reader.onloadend = () => 
            uploadImage(reader.result);
        ;
        reader.onerror = () => 
            console.error('AHHHHHHHH!!');
            setErrMsg('something went wrong!');
        ;
    ;

    const uploadImage = async (base64EncodedImage) => 
        console.log(base64EncodedImage)
        try 
            await fetch('image/upload', 
                method: 'POST',
                body: JSON.stringify( data: base64EncodedImage ),
                headers:  'Content-Type': 'application/json' ,
            );
            setFileInputState('');
            setPreviewSource('');
            setSuccessMsg('Image uploaded successfully');
         catch (err) 
            console.error(err);
            setErrMsg('Something went wrong!');
        
    ;
    return (
        <div>
            /* <h1 className="title">Upload an Image</h1> */
            <Alert msg=errMsg type="danger" />
            <Alert msg=successMsg type="success" />
            <form onSubmit=handleSubmitFile className="form">
                <input
                    id="fileInput"
                    type="file"
                    name="image"
                    onChange=handleFileInputChange
                    value=fileInputState
                    className="form-input"
                />
                <button className="btn" type="submit">
                    Submit
                </button>
            </form>
            previewSource && (
                <img
                    src=previewSource
                    
                    style= height: '300px' 
                />
            )
        </div>
    );

这是我的 image.js 路线

const express = require('express');
const router = express.Router();
const  cloudinary  = require('../utils/cloudinary');


router.get('/api/images', async (req, res) => 
  const  resources  = await cloudinary.search
      .expression('folder:dev_setups')
      .sort_by('public_id', 'desc')
      .max_results(30)
      .execute();

  const publicIds = resources.map((file) => file.public_id);
  res.send(publicIds);
);

router.post('api/upload', async (req, res) => 
  try 
      const fileStr = req.body.data;
      const uploadResponse = await cloudinary.uploader.upload(fileStr, 
          upload_preset: 'dev_setups',
      );
      console.log(uploadResponse);
      res.json( msg: 'yaya' );
   catch (err) 
      console.error(err);
      res.status(500).json( err: 'Something went wrong' );
  
);


module.exports = router;

这是我的 Cloudinary 文件信息:

require('dotenv').config();

const cloudinary = require('cloudinary').v2;
cloudinary.config(
    cloud_name: process.env.CLOUDINARY_NAME,
    api_key: process.env.CLOUDINARY_API_KEY,
    api_secret: process.env.CLOUDINARY_API_SECRET,
);

module.exports =  cloudinary ;

这是我的 App.js 文件:

import React, useState from 'react';
import Navbar, Nav, NavDropdown, Form, FormControl from 'react-bootstrap';
import Button from '@material-ui/core/Button';
import 'bootstrap/dist/css/bootstrap.min.css';
import Route, Router, useHistory from "react-router-dom";
import useCookies from 'react-cookie';
import './App.css';
import LandingPage from './components/profile/LandingPage';
import ProfilePage from './components/profile/ProfilePage';
import Homepage from './components/profile/Homepage';
import AddCat from './components/cats/AddCat';
import ProtectedRoute from './components/profile/ProtectedRoute';
import DisplayCats from './components/cats/DisplayCats';
import MyMap from './components/map/MapContainer';
import MyImage from './components/image';
// import AddFriend from './components/AddFriend' const url =
// 'https://api.cloudinary.com/v1_1/djcngbd59/image/upload'; const preset =
// 'atmhk5x9'

const App = () => 

    const cookieName = 'straytracker';
    const [cookies,
        setCookie,
        removeCookie] = useCookies([cookieName]);

    const history = useHistory();

    let userInfo = false;

    function isEmpty(obj) 
        return Object
            .keys(obj)
            .length === 0;
    

    if (!isEmpty(cookies)) 
        try 
            // jwtDecode just grabs the token. It does not validate the token. userInfo will
            // hold the user info in an object. If no jwt found, userInfo will hold the
            // false value.
            userInfo = cookies.straytracker;
         catch 
            //if token is not found, send user to landing page.
            history.push("/");
            console.log(cookies)
        
    

    console.log(userInfo, 'userinfo check')
    const [user,
        setUser] = useState(userInfo);

    const handleLogin = e => 
        e.preventDefault();
        try 
            userInfo = cookies.straytracker;
            setUser(userInfo);

            history.push("/home");
            window
                .location
                .reload(false);
            alert('You have successfully logged in')
         catch 
            alert('No token found')
            history.push("/");
        
    

    const handleLogout = e => 
        e.preventDefault();
        setUser(false);
        window
            .location
            .reload(false);
        removeCookie(cookieName, path: '/');
    

    const setCookieApp = (jwt) => 
        // let d = new Date();
        setCookie(cookieName, jwt)
    ;

    return (
        <div className="App">
            <header className="App-header">

                <Navbar bg="light" expand="lg">
                    <Navbar.Brand href="/home">Stray Tracker</Navbar.Brand>
                    <Navbar.Toggle aria-controls="basic-navbar-nav"/>
                    <Navbar.Collapse id="basic-navbar-nav">
                        <Nav className="mr-auto">
                            <Nav.Link href="/home">Home</Nav.Link>
                            <Nav.Link href="/map">View Map</Nav.Link>
                            <Nav.Link href="/report">Add Cat</Nav.Link>
                            <Nav.Link href="/profile">Profile</Nav.Link>
                            <Nav.Link href="/upload">Upload Image</Nav.Link>
                            <NavDropdown title="More" id="basic-nav-dropdown">
                                <NavDropdown.Item href="/AddFriend">Add Friend</NavDropdown.Item>
                                /* <NavDropdown.Item href="#action/3.3">Something</NavDropdown.Item> */
                                <NavDropdown.Divider/> /* <NavDropdown.Item href="#action/3.4">Separated link</NavDropdown.Item> */
                            </NavDropdown>
                        </Nav>
                        <Button color="secondary" onClick=handleLogout>
                            Logout
                        </Button>
                        <Form inline>
                            <FormControl type="text" placeholder="Search" className="mr-sm-2"/>
                            <Button variant="outlined">Search</Button>
                        </Form>
                    </Navbar.Collapse>
                </Navbar>
            </header>

            <Router history=history>
                /* <ProtectedRoute exact path='/home' user=userInfo ? user:null component=Homepage handleLogout=handleLogout/> */
                <Route
                    exact
                    path='/'
                    handleLogin=handleLogin
                    render=props => <LandingPage...props
                    user=user
                    handleLogin=handleLogin
                    setCookieApp=setCookieApp/>/>
                <ProtectedRoute
                    exact
                    path='/home'
                    user=user
                    component=Homepage
                    handleLogout=handleLogout/>
                <ProtectedRoute
                    exact
                    path='/profile'
                    user=user
                    component=ProfilePage
                    handleLogout=handleLogout/>
                <ProtectedRoute
                    exact
                    path='/report'
                    user=user
                    component=AddCat
                    handleLogout=handleLogout/> /* <Route
                    exact
                    path='/map'
                    user=user
                    component=MapContainer
                    handleLogout=handleLogout/> */
                <ProtectedRoute
                    exact
                    path='/cats'
                    render=props => <DisplayCats ...props user=user/>/>
                <ProtectedRoute
                    exact
                    path='/upload'
                    user=user
                    component=MyImage
                    handleLogout=handleLogout/>
                <Route exact path='/map' render=props => <MyMap ...props user=user/>/> /* <ProtectedRoute exact path='/AddFriend' user=user component=AddFriend /> */

            </Router>

        </div>
    );


export default App

这是我的Server package.json


  "name": "server",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "proxy": "http://localhost:3001",
  "scripts": 
    "start": "nodemon index2.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  ,
  "author": "",
  "license": "ISC",
  "dependencies": 
    "bcrypt": "^5.0.0",
    "body-parser": "^1.19.0",
    "cloudinary": "^1.23.0",
    "config": "^3.3.2",
    "cookie-parser": "^1.4.5",
    "cors": "^2.8.5",
    "debug": "^4.3.1",
    "dotenv": "^8.2.0",
    "express": "^4.17.1",
    "http-errors": "^1.8.0",
    "jade": "^1.11.0",
    "joi": "^17.2.1",
    "jsonwebtoken": "^8.5.1",
    "mongoose": "^5.10.15",
    "morgan": "^1.10.0",
    "multer": "^1.4.2",
    "nodemon": "^2.0.6",
    "uuid": "^8.3.1"
  


【问题讨论】:

【参考方案1】:

查看您共享的代码,我看到您为api/upload 定义了一个POST 路由,但是uploadImage 调用将请求发送到image/upload,这不是一个定义的路由。您能否将uploadImage 中的端点从image/upload 更新为api/upload 并再次测试上传。

【讨论】:

以上是关于React 和 Node 应用程序未将图像上传到 Cloudinary,404 错误没有解释的主要内容,如果未能解决你的问题,请参考以下文章

将图像文件从 React 前端上传到 Node/Express/Mongoose/MongoDB 后端(不工作)

如何在上传后立即接收 Cloudinary 图像 URL(React JS 和 Node Js)?

从 Postgres 返回图像 url 到前端 - Node / React

node.js / react 使用 graphql createReadStream 上传文件不是函数

React-native node.js 显示错误:多部分:使用 react-native-image-picker 上传图像时未找到边界

使用 MongoDB、express、node 和 react 上传图片