Next.js前端上传图片至Cloudinary时遭遇CORS错误求助
场景描述
首次使用MERN栈开发用户头像上传功能,前端代码如下:
// Settings.tsx import React, { useEffect, useState } from "react"; import axios from "axios"; import Image from "next/image"; import iconDefault from "../assets/random/user.png"; const Settings = () => { const [isEditing, setIsEditing] = useState<boolean>(false); const [file, setFile] = useState<any | null>(null); const [picture, setPicture] = useState<any | null>(null); const cookies = new Cookies(); const user = getUserCookie(); const [updatedUser, setUpdatedUser] = useState<User>(user); const handleEdit = () => { setIsEditing(!isEditing); }; const handleInputChange = ( e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement> ) => { const { name, value } = e.target; setUpdatedUser((prevUser) => ({ ...prevUser, [name]: value, })); }; const upload_preset = "....."; const cloud_name = "....."; const submitImage = async () => { const data = new FormData(); data.append("file", file); data.append("upload_preset", upload_preset); data.append("cloud_name", cloud_name); try { const res = await axios.post( `https://api.cloudinary.com/v1_1/${cloud_name}/image/upload`, data ); const cloudinaryUrl = res.data.secure_url; setPicture(cloudinaryUrl); const updatedUserWithImage = { ...updatedUser, icon: cloudinaryUrl }; await editUser(updatedUserWithImage); } catch (err) { console.log("error uploading icon", err); } }; const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault(); try { if (file) { await submitImage(); } else { await editUser(updatedUser); } window.location.reload(); } catch (err) { console.log("error updating icon: ", err); } }; const editUser = async (updatedUser: User) => { const token = cookies.get("token"); try { await axios.patch( process.env.MONGODB_URL + `/users/${user?._id}`, updatedUser, { headers: { Authorization: `Bearer ${token}`, }, } ); const response = await axios.get( process.env.MONGODB_URL + `/users/${user?._id}`, { headers: { Authorization: `Bearer ${token}`, }, } ); const updatedUserFromServer = response.data; document.cookie = `user=${JSON.stringify(updatedUserFromServer)}; path=/`; console.log("Updated User:", updatedUserFromServer); } catch (err) { console.log("error updating user: ", err); } }; return ( <div className="settings"> <main> <header className="header__welcome card "> <div> {user ? <h1>Hello, {user.name}!</h1> : <h1>Loading user...</h1>} <h2>Edit here your profile info</h2> </div> </header> <div className="form-container"> <form onSubmit={handleSubmit} className="form-settings"> <div className="form-settings__left"> <div> {user.icon ? ( <Image className="icon-settings" src={user.icon} width="400" height="400" alt="icon" /> ) : ( <Image className="icon-settings" src={iconDefault} width="400" height="400" alt="iconDefault" /> )} </div> <div className="rainbow__button"> <label htmlFor="icon">Edit profile picture</label> <input type="file" name="icon" className="input-settings" onChange={(e) => setFile(e.target.files?.[0] || null)} /> </div> </div> {......} <div className="buttons"> <button className="buttons__addtask rainbow__button" type="submit" > Save changes </button> <hr></hr> <DeleteUser /> </div> </div> </form> </div> </main> </div> ); }; export default Settings;
错误信息
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://api.cloudinary.com/v1_1/---/image/upload. (Reason: header ‘authorization’ is not allowed according to header ‘Access-Control-Allow-Headers’ from CORS preflight response).
XHRPOST https://api.cloudinary.com/v1_1/---/image/upload
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://api.cloudinary.com/v1_1/----/image/upload. (Reason: CORS request did not succeed). Status code: (null).
error uploading icon
已将Cloudinary上传预设设为"unsigned",之前曾因MongoDB用户文档缺少"icon"字段出现过类似问题,添加后恢复正常,且成功修改过几次头像,如今问题再次出现。
解决方案
1. 清除Cloudinary请求的Authorization头
问题核心是Axios可能全局配置了Authorization头,导致请求Cloudinary时自动带上该头,但Cloudinary的CORS策略不允许这个头。修改submitImage函数中的请求配置,显式清除headers:
const res = await axios.post( `https://api.cloudinary.com/v1_1/${cloud_name}/image/upload`, data, { headers: {} } // 重置headers,避免携带Authorization );
2. 再次验证Cloudinary上传预设
- 确认上传预设的模式为Unsigned,没有误切换为Signed。
- 检查预设的CORS配置:如果设置了
Allowed Origins,确保包含你的前端域名(比如http://localhost:3000或生产环境域名),若未设置则保持默认即可。
3. 优化Cookie更新方式
当前代码直接通过document.cookie修改用户Cookie,这种方式存在安全风险且可能导致缓存问题。建议由后端接口返回Set-Cookie头来更新用户Cookie,前端无需手动操作。
4. 增强错误排查
在submitImage的catch块中打印更详细的错误信息,方便定位问题:
catch (err) { console.log("error uploading icon", err.response?.data || err.message || err); }
内容的提问来源于stack exchange,提问作者queercoded

