[ВНИМАНИЕ]: Мне необходимо использовать серверную страницу, в противном случае я бы использовал компонент «клиентской стороны» с аксиомами.
Я пытаюсь загрузить файл на внешний экспресс-сервер. В любом случае, при отправке на маршрут API req.files.file пуст, не определен или просто пуст.
Я хотел бы отметить, что файл обнаруживается, когда атрибут действия срабатывает после отправки формы. console.info(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.info(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