Я разрабатываю веб-приложение MERN stack, которое позволяет продавцам размещать свои комнаты в аренду, а пользователям искать и выбирать для них лучшую комнату.
Всякий раз, когда я выполняю функцию Post Review, генерируется ошибка «AxiosError {сообщение: «Запрос не выполнен с кодом состояния 500», имя: «AxiosError», код: «ERR_BAD_RESPONSE». Какая проблема будет в моем коде на бэкэнде или во внешнем интерфейсе, когда я отправлю сообщение во внешнем интерфейсе?
Я использовал промежуточное программное обеспечение, такое как isBuyer, которое позволяет только пользователю, являющемуся покупателем, публиковать отзыв о комнате.
Итак, вот мой код:
ФРАНТЕНДНЫЙ КОД:
api.js (это часть всего кода, в которой вызываются поддерживаемые API)
import axios from 'axios';
const API_BASE_URL = 'http://localhost:5001/api/v1';
export const postReview = async (reviewData, id) => {
try {
const response = await axios.post(`${API_BASE_URL}/reviews/post-reviews/${id}`, reviewData, {
withCredentials: true,
});
return response;
} catch (error) {
console.error('Error posting review:', error.response ? error.response.data : error.message);
throw error;
}
};
PostReview.jsx (консоль выдает ошибку в строке: 15)
import React, { useState } from 'react';
import { postReview } from '../api';
const PostReview = ({ id }) => {
const [formData, setFormData] = useState({ rating: '', review: '' });
const [error, setError] = useState(null);
const handleChangeEvent = (e) => {
setFormData({...formData, [e.target.name]: e.target.value });
};
const handleSubmit = async (e) => {
e.preventDefault();
try {
const res = await postReview(formData, id); /* --------- ERROR ---------- */
console.info(res.data);
}
catch (error) {
console.error('Error submitting review:', error);
setError(error.response ? error.response.data.message : error.message);
}
};
return (
<div>
<form onSubmit = {handleSubmit}>
<input
type = "number"
min = {1}
max = {5}
name = "rating"
value = {formData.rating}
placeholder='Rating'
onChange = {handleChangeEvent}
/>
<input
type = "text"
name = "review"
value = {formData.review}
placeholder='Review'
onChange = {handleChangeEvent}
/>
<button type = "submit">Post</button>
</form>
{error && <p>Error: {error}</p>}
</div>
);
};
export default PostReview;
SingleHostel.jsx (здесь используется компонент PostReview)
import React, { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import { getSingleHostel } from '../api';
import PostReview from '../components/PostReview';
import { useUser } from '../context/userContext';
const SingleHostel = () => {
const [room, setRoom] = useState([]);
const { id } = useParams();
const { user } = useUser();
useEffect(() => {
const fetchHostel = async () => {
try {
const res = await getSingleHostel(id);
setRoom(res.data.hostel);
console.info(res.data.hostel);
} catch (error) {
console.info(error.response ? error.response.data.message : error.message);
}
};
fetchHostel();
}, [id]);
return (
<div>
<div>
<h1>{room.name}</h1>
<h1>{room.location}</h1>
<h1>{room.address}</h1>
<h1>{room.rent}</h1>
<h1>{room.description}</h1>
<h1>{room.status}</h1>
</div>
{user?.isBuyer ? <div> <PostReview id = {room._id} /> </div> : null}
</div>
);
};
export default SingleHostel;
UserContext.jsx (пользовательские данные формы React Context API)
import React, { createContext, useContext, useState, useEffect } from 'react';
import { getCurrentUser as fetchCurrentUser } from '../api';
const UserContext = createContext();
export const useUser = () => {
return useContext(UserContext);
};
export const UserProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchUser = async () => {
try {
const userData = await fetchCurrentUser();
setUser(userData);
} catch (error) {
console.error('Error fetching current user:', error.message);
}
setLoading(false);
};
fetchUser();
}, []);
return (
<UserContext.Provider value = {{ user, setUser, loading }}>
{children}
</UserContext.Provider>
);
};
БЕЗОПАСНЫЙ КОД:
обзор.controllers.js
import {Review} from "../models/review.model.js";
const postReviews = async(req, res) => {
try{
const {id} = req.params;
const {rating, comment} = req.body;
if ([rating, comment].some((data) => data.trim() === "")){
return res.status(400).json({message: "Please fill all the fields."})
}
const review = await Review.create({user: req.user._id, hostel : id, rating, comment});
res.status(201).json({message: "Review created successfully.", review})
}
catch(err){
res.status(500).json({message: "Internal server error."})
}
}
const getAllReviewsForHostel = async(req, res) => {
try{
const {id} = req.params;
const reviews = await Review.find({hostel: id}).populate("user", "-password -refreshToken -isSeller -isBuyer");
if (!reviews){
return res.status(404).json({message: "No reviews found."})
}
res.status(200).json({message: "Reviews found successfully.", reviews})
}
catch(error){
res.status(500).json({message: `Reviews fetching unsuccessfull. ERROR : ${error.message}`});
}
}
export {postReviews, getAllReviewsForHostel};
userAuthmiddleware.js
import jwt from "jsonwebtoken";
import { User } from "../models/user.model.js";
const verifyUser = async (req, res, next) => {
try {
const token = req.cookies?.accessToken;
if (!token){
return res.status(400).json({
message : "Unauthorised Request! Token not found",
})
}
const decodedToken = await jwt.verify(token, process.env.ACCESS_TOKEN_SECRET);
const user = await User.findById(decodedToken._id).select("-password -refreshToken");
if (!user){
return res.status(400).json({
message : "Invalid decoded token",
})
}
req.user = user;
next();
}
catch (error){
return res.status(400).json({
message : `Invalid user. Authentication Failed ! ERROR : ${error.message}`,
})
}
}
export {verifyUser};
промежуточное программное обеспечение userIsBuyer
import { User } from "../models/user.model.js";
const isBuyerAuth = async (req, res, next) => {
try{
const user = await User.findById(req.user.id);
if (user.isBuyer){
next();
}
else{
return res.status(403).json({message: "You do not have access to this route."});
}
}
catch(error){
return res.status(500).json({message: `User buyer authentication error. ${error.message}`});
}
}
export {isBuyerAuth};
Обзор.model.js
import mongoose from "mongoose";
const reviewSchema = new mongoose.Schema({
user : {
type : mongoose.Schema.Types.ObjectId,
ref : "User",
},
hostel : {
type : mongoose.Schema.Types.ObjectId,
ref : "Hostel",
},
rating : {
type : Number,
required : true,
min : 1,
max : 5,
},
comment : {
type : String,
required : true,
maxLength : 500,
},
datePosted : {
type : Date,
default : Date.now,
},
}, {timestamps : true});
export const Review = new mongoose.model("Review", reviewSchema);
обзор.routes.js
import {Router} from "express";
import { postReviews, getAllReviewsForHostel } from "../controllers/reviews.controllers.js";
import { isBuyerAuth } from "../middlewares/user.isBuyer.middleware.js";
import { verifyUser } from "../middlewares/user.auth.middleware.js";
const router = Router();
router.route("/post-reviews/:id").post(verifyUser, isBuyerAuth, postReviews);
router.route("/get-all-reviews/:id").get(verifyUser, getAllReviewsForHostel);
export default router;
приложение.js
import express from 'express';
import cors from 'cors';
import userRouter from './routes/user.routes.js';
import hostelRouter from './routes/hostel.routes.js';
import reviewRouter from './routes/review.routes.js';
import bookmarkRouter from './routes/bookmark.routes.js';
import cookieParser from 'cookie-parser';
const app = express();
const allowedOrigins = ['http://localhost:5174']; // Specify your frontend origin
const corsOptions = {
origin: allowedOrigins,
credentials: true, // This is required to allow cookies with CORS
};
app.use(cors(corsOptions));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
app.use('/api/v1/users', userRouter);
app.use('/api/v1/hostels', hostelRouter);
app.use('/api/v1/reviews', reviewRouter);
app.use('/api/v1/bookmarks', bookmarkRouter);
export default app;
Я хотел убедиться, что когда пользователь (покупатель) заходит на страницу SingleHostel, он видит информацию о хостеле и у него есть возможность опубликовать отзыв об этом хостеле.
Я попытался протестировать postReview с помощью почтальона, так что обзор успешно публикуется, но когда я пытаюсь сделать это с помощью формы внешнего интерфейса, это выдает мне ошибку.
Бэкенд скорее всего. console.info ошибка в серверной части в блоке catch для дальнейшей отладки.
Я протестировал его с помощью Postman, поэтому внутренний код работает правильно. Отзыв успешно опубликован. Но когда сообщение вводится через интерфейс, возникает ошибка.
Некоторые наблюдения или комментарии:
с учетными данными: правда
Необходимо указать withCredentials: true для всех запросов к серверной части, поскольку в этом приложении используется файл cookie. Из этого вопроса видно, что это было сделано для URL-адреса /reviews/post-reviews/. Пожалуйста, проверьте, предоставляется ли он также для всех других запросов из внешнего интерфейса.
Распространенной ошибкой в этом случае является отсутствие параметра withCredentials: true в запросе на регистрацию. Это необходимо и в этом случае. Например, см. этот случай Невозможно получить доступ к файлу cookie авторизациивведите сюда описание ссылки.
Причина для обсуждения этого вопроса заключается в том, что способы обработки файлов cookie тестовыми клиентами и стандартными браузерами различаются.
Используйте трассировку стека
Для дальнейшей отладки используйте трассировку стека, созданную Express. Это можно отобразить в консоли браузера, как показано ниже. Аксиос имеет то же самое в своем ответе. Минимальный пример см. в ответе в сообщении здесь Запрос Axios GET на получение твитов для конкретного пользователя возвращает ошибку 500, маршрут не достигнут.
Этот вопрос похож на: Проблемы с получением запроса React/Axios API (CORS и внутренняя ошибка сервера 500). Если вы считаете, что это другое, отредактируйте вопрос, поясните, чем он отличается и/или как ответы на этот вопрос не помогают решить вашу проблему.