[注意]:我需要使用服务器页面,否则我会在 axios 中使用“客户端”组件。
我正在尝试将文件上传到我的外部快递服务器。无论如何,当将其发送到 API 路由时,
req.files.file
为空、未定义或只是空白。
我想提一下,提交表单后触发操作属性时会检测到该文件。
console.log(avatar)
返回以下内容:
file: File {
size: 476026,
type: 'image/jpeg',
name: 'Delta-Force-Operator-in-a-Chinook_4x-scaled.jpg',
lastModified: 1716527617781
}
无论如何,我面临的麻烦与 Express 服务器有关。我使用一个名为
express-fileupload
的库,为了从即将到来的请求中获取文件,我需要执行类似 req.files.file
的操作,其中 file
是您输入的名称。
exports.uploadObject = asyncHandler(async (req, res, next) => {
// Prevent execution of code if there is not file in request
console.dir(req.files);
if (!req.files || Object.keys(req.files).length === 0 || !req.files.file) {
return next(new ErrorResponse(`No file uploaded`, 400));
}
/*
YADAYADAYADA
*/
// Return object
res.status(201).json({
success: true,
data: "success"
});
});
});
});
无论我做什么,服务器都不会收到文件,这就是终端上显示的内容
{}
,一个实际的空对象,其中甚至没有字段或值。
这是我在服务器页面中的表单:
const upgradeAvatar = async (formData) => {
'use server'
const avatar = formData.get('file')
const rawFormData = {
userId: auth?.data?._id,
username: auth?.data?.username,
userEmail: auth?.data?.email,
onModel: 'User',
album: 'profile-avatars',
file: avatar,
}
// Output
console.log(rawFormData.file);
// My function to external API
await uploadFile(rawFormData)
}
<form action={upgradeAvatar}>
<label htmlFor="file" className="form-label">
File
</label>
<input
id="file"
name="file"
type="file"
className="form-control mb-3"
accept={`image/*`}
/>
<FormButtons />
</form>
最终我无法实现我想做的事情,所以我决定创建一个辅助文件,其中放置所有表单的逻辑和 Api 请求。
'use client'
import { fetchurl, getAuthTokenOnServer } from '@/helpers/setTokenOnServer'
import { useState } from 'react'
import { toast } from 'react-toastify'
import Image from 'next/image'
import UseProgress from '@/components/global/useprogress'
import axios from 'axios'
const Form = ({ auth }) => {
const [coverData, setCoverData] = useState({
file: null,
filename: `Choose file`,
fileurl: `https://static.vecteezy.com/system/resources/previews/005/337/799/original/icon-image-not-found-free-vector.jpg`,
})
const { file, filename, fileurl } = coverData
const [uploadPercentage, setUploadPercentage] = useState(0)
const [error, setError] = useState(false)
const [btnText, setBtnTxt] = useState('Submit')
const upgradeAvatar = async (e) => {
e.preventDefault()
setBtnTxt('Submit...')
const token = await getAuthTokenOnServer()
const res = await axios.put(
`http://localhost:5000/api/v1/uploads/uploadobject`,
{
userId: auth?.data?._id,
username: auth?.data?.username,
userEmail: auth?.data?.email,
onModel: 'User',
file: file,
album: 'profile-covers',
},
{
headers: {
'Content-Type': 'multipart/form-data',
Authorization: `Bearer ${token.value}`,
},
onUploadProgress: (ProgressEvent) => {
setUploadPercentage(
parseInt(
Math.round(ProgressEvent.loaded * 100) / ProgressEvent.total
)
)
setTimeout(() => setUploadPercentage(0), 10000)
},
}
)
await fetchurl(`/auth/updateavatar`, 'PUT', 'no-cache', {
cover: res.data.data._id,
})
}
const resetForm = () => {
setCoverData({
file: null,
filename: `Choose file`,
fileurl: `https://static.vecteezy.com/system/resources/previews/005/337/799/original/icon-image-not-found-free-vector.jpg`,
})
}
return (
<form onSubmit={upgradeAvatar}>
<label htmlFor="cover" className="form-label">
File
</label>
<input
id="cover"
name="file"
label={file}
onChange={(e) => {
const myFile = e.target.files[0]
let preview = ''
if (myFile instanceof Blob || myFile instanceof File) {
preview = URL.createObjectURL(myFile)
}
setCoverData({
file: myFile,
filename: myFile.name,
fileurl: preview,
})
}}
type="file"
className="form-control mb-3"
placeholder={fileurl}
accept={`image/*`}
/>
<UseProgress percentage={uploadPercentage} />
<button type="submit" className="btn btn-secondary btn-sm float-start">
{btnText}
</button>
<button
type="button"
className="btn btn-secondary btn-sm float-end"
onClick={resetForm}
>
Reset
</button>
</form>
)
}
export default Form
然后我只是将 Form 组件调用到我的服务器页面。
import { fetchurl } from '@/helpers/setTokenOnServer'
import Form from './form'
async function getAuthenticatedUser() {
const res = await fetchurl(`/auth/me`, 'GET', 'no-cache')
return res
}
const UpdateAvatar = async ({ params, searchParams }) => {
const auth = await getAuthenticatedUser()
// Redirect if user is not logged in
;(auth?.error?.statusCode === 401 || !auth?.data?.isOnline) &&
redirect(`/auth/login`)
return <Form auth={auth} />
}
export default UpdateAvatar