You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React注册表单提交出现500内部服务器错误及JSON解析异常求助

注册表单提交时出现500内部服务器错误及JSON解析错误

问题现象

提交React注册表单时触发两个错误:

POST http://localhost/auth/register 500 (Internal Server Error)
SubmitRegistration error: SyntaxError: Unexpected token '<', "JSON

表单支持用户名、邮箱、密码提交及头像上传。

相关代码

表单组件代码

<form
    onSubmit={(evt) => {
        RegistrationForm = document.getElementById('RegistrationForm');
        NameInput = document.querySelector('#nameInput')
        EmailInput = document.querySelector('#emailInput')
        PasswordInput = document.querySelector('#passwordInput')
        ConfirmInput = document.querySelector('#confirm_passwordInput')
        ProfileInput = document.querySelector("#profile_picInput")
        var FormElements = {
            RegistrationForm,
            NameInput,
            EmailInput,
            PasswordInput,
            ConfirmInput,
        }
        HandleSignUpSubmit(evt, FormElements, profileImage, registerURL, dispatchFunctions, resetErrorFields)
    }}
    id="RegistrationForm"
    encType="multipart/form-data"
    className={`bg-[#f2e798] w-11/12 md:w-9/12 mx-auto lg:w-6/12 mt-[20px] py-10`}>
    <div
        id="Shell"
        className={`w-11/12 mx-auto ${FormStyle}`}
    >
        <div>
            <label htmlFor="username">Username</label>
            <input
                name="username"
                id="nameInput"
                type="text"
                placeholder="Type your username here"
                required
                className=""
                value={name}
                onChange={(evt) => onChangeHandler(evt, setName, resetErrorFields)}
            />
            <div id="usernameError" className="ErrorDiv">
                {usernameError != null && usernameError.length > 0 && RenderError(usernameError)}
            </div>
        </div>
        <div>
            <label htmlFor="email">Email</label>
            <input
                name="email"
                id="emailInput"
                type="text"
                placeholder="Type your email here"
                required
                className=""
                value={email}
                onChange={(evt) => onChangeHandler(evt, setEmail, resetErrorFields)}
            />
            <div id="emailError" className="ErrorDiv">
                {emailError != null && emailError.length > 0 && RenderError(emailError)}
            </div>
        </div>
        <div>
            <label htmlFor="profile_pic">Profile picture</label>
            <input
                name="profile_pic"
                id="profile_picInput"
                type="file"
                placeholder="Upload an image htmlFor your your profile picture here"
                className="file:rounded-lg file:font-['DecoTech'] file:bg-[#99cbae] file:text-white cursor-pointer"
                onChange={(evt) => { HandleFileChange(evt, setImage) }}
            />
        </div>
        <div>
            <label htmlFor="password">password</label>
            <input
                name="password"
                id="passwordInput"
                type="password"
                placeholder="Type your password here"
                required
                className=""
                value={password}
                onChange={(evt) => onChangeHandler(evt, setPassword, resetErrorFields)}
            />
            <div id="passwordError" className="ErrorDiv">
                {passwordError != null && passwordError.length > 0 && RenderError(passwordError)}
            </div>
        </div>
        <div>
            <label htmlFor="confirm_password">Confirm your password</label>
            <input
                name="confirm_password"
                id="confirm_passwordInput"
                type="password"
                placeholder="Re-type your password here to confirm"
                required
                className=""
                value={confirmPass}
                onChange={(evt) => onChangeHandler(evt, setConfirmPass, resetErrorFields)}
            />
            <div
                id="confirmError"
                className="ErrorDiv">
                {confirmError != null && confirmError.length > 0 && RenderError(confirmError)}

            </div>
        </div>
        <div id="ButtonWrapper"
            className="grid sm:flex"
        >
            <button
                type="submit"
                className={SubmitStyle}
                value="Submit"
            >Submit</button>
            <button
                type="button"
                className={CancelStyle}
                value="Cancel"
                onClick={useCallback(() => navigate(-1))}
            >Cancel</button>
        </div>
        <hr className="my-[25px] h-[2px] border-[2px]" />
        <h2 className="my-10 text-center text-lg">Already have an account with us?</h2>
        <button
            type="button"
            className="block rounded-full p-[10px] active:translate-x-[5px] active:translate-y-[5px] cursor-pointer border-white border-2 text-center w-[150px] select-none text-black mx-auto hover:bg-[#d48518] bg-[#e48f1a] text-center"
            onClick={useCallback(() => GoSignIn(navigate), [navigate])}
        >Log In</button>
    </div>
</form>

文件上传处理函数

function HandleFileChange(evt, setImage) {
        const file = evt.target.files[0]; 
        const reader = new FileReader(); 
        reader.readAsDataURL(file); 
        reader.onload = () => {
            setImage(reader.result);
        }
    }

Fetch提交函数

//apiURL = "http://localhost/auth/register"
async function SubmitRegistration(data, apiURL, dispatchFunctions) {
    console.log("Registrating user")
    const {
        username,
        email,
        password,
        confirm_password,
        profile_pic,
    } = data;
    console.log("profile_pic: ", profile_pic)
    const formData = new FormData;
    formData.append("username", username);
    formData.append("email", email);
    formData.append("password", password);
    formData.append("confirm_password", confirm_password);
    formData.append("profile_pic", profile_pic);
    for (var key of formData.entries()) {
        console.log(key[0] + ', ' + key[1])
    }
    const {
        GoHome,
        toggleDisplayAccountLink,
        setNewUser,
    } = dispatchFunctions;

    await fetch(apiURL, {
        method: "POST",
        headers: { "Content-Type": "multipart/form-data" },
        body: formData
    })
        .then(async response => {
            if (response.ok) {
                console.log("Registration is successful.")
                await response.json()
                    .then(data => {
                        localStorage.setItem("user", JSON.stringify(data.user))
                        localStorage.setItem('token', data.token)
                        //setNewUser and toggleDisplayAccoutLink updates the header bar to contain
                        //data about the logged in user
                        setNewUser(data.user)
                        toggleDisplayAccountLink(true),
                            GoHome();

                    })
            }
            else {
                const result = await response.json()
                console.log("Registration failed with status code: ", result.error)
                RenderErrorArray(result.error, dispatchFunctions)
            }
        })
        .catch(error => {
            console.log("SubmitRegistration error: ", error)
        })
}

服务端路由配置

const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, "public/uploads")
    },
    filename: function (req, file, cb) {
        const ext = path.extname(file.originalname);
        const filename = `${Date.now()}-${file.filename}${ext}`;
        cb(null, filename)
    }
});  

const upload = multer({ storage: storage }); 

router.post('/register', cors(), upload.single('profile_pic'), authController.Register)

服务端控制器代码

exports.Register = [
    body("username")
        .trim()
        .isLength({ min: 1 })
        .withMessage("You must type your username.")
        .escape(),
    body("email")
        .trim()
        .isLength({ min: 1 })
        .withMessage("You must type your email address. ")
        .custom((value) => {
            if (!checkEmail(value)) {
                throw new Error("The email format is not valid. It must be something along the lines of Bob@email.com.");
            }
            return true;
        }),
    body("password")
        .trim()
        .isLength({ min: 4 })
        .withMessage("Your password must be at least 4 characters long."),
    body("profile_pic"),
    body("confirm_password")
        .trim()
        .isLength({ min: 4 })
        .withMessage("Your confirmation password must be at least 4 characters long.")
        .custom((value, { req }) => {
            if (value != req.body.password) {
                throw new Error("Your password and confirmation password should match.")
            }
            //this is necessary to indicate that the validation passed
            return true
        }),
    async (req, res, next) => {
        const {
            username,
            email,
        } = req.body;

        const errors = validationResult(req);

        const UserList = await User.find({})

        UserList.forEach(val => {
            if (val.username == username.trim()) {
                const obj = {
                    param: "username",
                    msg: "That username already exists in our database."
                }
                errors.errors.push(obj)
            }
            if (val.email.toLowerCase() == email.trim().toLowerCase()) {
                const obj = {
                    param: "email",
                    msg: "That email already exists in our database."
                }
                errors.errors.push(obj)
            }
        })

        if (!errors.isEmpty()) {
            return res.status(400).json({ error: errors.array() });
        }
        try {
            const hashedPassword = await bcrypt.hash(req.body.password, 10)
            const obj = {
                username: username.replace(/\s/g, ''),
                email: email,
                password: hashedPassword,
                joinedDate: Date.now(),
            }

            if (req.files && req.files.profile_pic) {
                obj.profile_pic = req.files.profile_pic[0].buffer
            }

            const newUser = new User(obj);
            const result = await newUser.save();

            const savedUser = {
                username: result.username,
                email: result.email,
                joinedDate: result.joinedDate,
                profile_pic: result.profile_pic,
                id: result._id,
            }

            console.log("User is successfully created.")
            const token = jwt.sign(savedUser.toJSON(), process.env.JWT_SECRET, { expiresIn: 60 * 60 })
            return res.status(200).json({ user: savedUser, token, message: "User is successfully saved in the database" });
        } catch (e) {
            console.log("Error in trying to create new user: ", e.message)
            res.status(500).json({ error: e.message });
        }
    }
]

问题排查及解决方案

1. 客户端文件上传错误

HandleFileChange里把文件转成了Data URL(base64字符串),但服务端用multer接收的是原始文件对象,不是base64字符串,导致服务端无法解析文件抛出错误。
修复:直接保存文件对象而非base64:

function HandleFileChange(evt, setImage) {
    const file = evt.target.files[0]; 
    setImage(file);
}

2. Fetch请求头错误

手动设置Content-Type: multipart/form-data会导致浏览器无法自动生成正确的boundary分隔符,服务端无法解析FormData。
修复:删除Fetch的headers配置,让浏览器自动处理:

await fetch(apiURL, {
    method: "POST",
    body: formData
})

3. 服务端文件读取错误

使用upload.single('profile_pic')时,文件存在req.file而非req.files.profile_pic;同时multer文件名生成逻辑错误,file.filename应为file.originalname。
修复:

  • 修正multer文件名生成:
filename: function (req, file, cb) {
    const ext = path.extname(file.originalname);
    const filename = `${Date.now()}-${file.originalname.replace(ext, '')}${ext}`;
    cb(null, filename)
}
  • 修正控制器文件获取逻辑:
if (req.file) {
    obj.profile_pic = req.file.path; // 建议存文件路径,而非buffer到数据库
}

4. 服务端用户查询性能问题

User.find({})遍历所有用户检查重复,性能极差,改用数据库直接查询:

const existingUser = await User.findOne({
    $or: [
        { username: username.trim() },
        { email: email.trim().toLowerCase() }
    ]
});

if (existingUser) {
    if (existingUser.username === username.trim()) {
        errors.errors.push({ param: "username", msg: "That username already exists in our database." });
    }
    if (existingUser.email.toLowerCase() === email.trim().toLowerCase()) {
        errors.errors.push({ param: "email", msg: "That email already exists in our database." });
    }
}

5. JSON解析错误原因

客户端的SyntaxError是因为服务端返回了HTML错误页而非JSON,修复上述问题后,确保服务端所有错误都返回JSON格式即可解决。


内容的提问来源于stack exchange,提问作者antsmasher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 05:23:09