Reactjs 到 Laravel:在 FormData 中发送文件,返回文件字段为空,如何解决此错误?

问题描述 投票:0回答:1

在Postman客户端中操作成功完成。我收到响应并且文件已成功更新,但是问题出现在reactjs v18.2.0 react-redux v8.0.5

以下是我使用mutation发出post请求时得到的响应=>

{
    "message": "The file field is required.",
    "errors": {
        "file": [
            "The file field is required."
        ]
    }
}

Laravel 中的服务器端代码

以下为api路由

 // upload file
    Route::post('/document/upload-file', [DocumentController::class, 'uploadDocumentFile']);

DocumentController 的操作

// upload file and return file url
    public function uploadDocumentFile(Request $request)
    {
        $this->validate($request, [
            'file' => 'required|file|mimes:jpg,png,pdf|max:2048',
        ]);

        $file = $request->file('file');
        $fileUrl = $file->store('uploads/documents', 'public');

        return response()->json(['file_url' => $fileUrl]);
    }

ReactJs 中的客户端

帖子请求=>

  const [title, setTitle] = useState<string>("");
  const [body, setBody] = useState<string>("");
  const [file, setFile] = useState<File | "">("");

  const [uploadFile] = useUploadFileMutation();

  const handleFileUpload = async (submittedFile: File) => {
 
   try {
      const formData = new FormData();
      formData.append("file", submittedFile);
     
      const token = localStorage.getItem("token");
     
      const response: any = await uploadFile(formData).unwrap();

      // Check if the file_url is present in the response
      const fileUrl = response;
      if (fileUrl) {
        console.log("File Url:", fileUrl);
      } else {
        console.error("File URL not found in the response.");
      }
    } catch (error) {
      // Handle errors
      console.error("Error uploading file:", (error as Error).message);
    }
  };

  const handleSubmit = async (e: React.FormEvent<HTMLElement>) => {
    e.preventDefault();
    if (file !== "") {
      console.log("File found ! Preparing the upload...");
      await handleFileUpload(file);
    }
  };

从 ui 获取文件的表单

    <form onSubmit={handleSubmit}>
          <div className="grid grid-cols-1 gap-5">
            <div>
              <label htmlFor="document-title"> Title </label>
              <FormInput type="text" name="title" id="document-title" value={title}
                onChange={(e) => setTitle(e.target.value)}
              />
            </div>
            <div>
              <label htmlFor="document-body"> Description </label>
              <FormInput type="textarea" name="answer" id="document-body" value={body}
                onChange={(e) => {
                  setBody(e.target.value);
                }} />
              <div className="max-w-xl my-6">
                <Dropzone onDrop={(acceptedFiles) => setFile(acceptedFiles[0])}>
                  {({ getRootProps, getInputProps }) => (
                    <section>
                      <div
                        {...getRootProps()}
                        className="w-full h-full relative"
                      >
                        <input
                          type="file"
                          name="file"
                          {...getInputProps()}
                        />
                        <p className="absolute left-[20%] top-[43%]">
                          Drag 'n' drop some files here, or click to select
                          files
                        </p>
                      </div>
                    </section>
                  )}
                </Dropzone>
              </div>
            </div>
            <div>
              <button
                type="submit"
              >
                Submit
              </button>
            </div>
          </div>
        </form>

RTK 突变请求:

    uploadFile: builder.mutation({
      query: (body) => ({
        url: `/document/upload-file`,
        method: "POST",
        formData: true,
        body,
      }),
    }),

ApiSlice

import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/dist/query/react";

// create api slice
export const apiSlice = createApi({
  reducerPath: "api",
  baseQuery: fetchBaseQuery({

    baseUrl: `https://example_server.com/api`,

    prepareHeaders: (headers) => {
      headers.set("X-Requested-With", "XMLHttpRequest");
      headers.set("Content-Type", "application/json");
      headers.set("Accept", "application/json");

      const token = localStorage.getItem("token");
      if (token) {
        headers.set("Authorization", `Bearer ${token}`);
      }
      return headers;
    },
  }),
  endpoints: (builder) => ({}),
});

文档控制器

<?php

namespace App\Http\Controllers;
use App\Models\Document;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class DocumentController extends Controller
{
    public function getAllDocuments()
    {
        $documents = Document::all();
        return response()->json($documents);
    }

    // public function show($id)
    // {
    //     $document = Document::find($id);
    //     return response()->json($document);
    // }

   

    public function storeDocuments(Request $request)
    {
        $this->validate($request, [
            'user_id' => 'required|exists:users,id',
            'files_title' => 'required|string',
            'files_description' => 'required|string',
            'file' => 'required|file|mimes:jpg,png,pdf|max:2048',
        ]);

        // Handle file upload and store it in the storage/uploads directory.
        $file = $request->file('file');
        $fileUrl = $file->store('uploads', 'public');

        // Create the document with the validated data and file URL.
        $document = Document::create([
            'user_id' => $request->user_id,
            'title' => $request->files_title,
            'body' => $request->files_description,
            'file_url' => $fileUrl,
            'position' => $request->position ?? 0,
        ]);

        return response()->json($document, 201);
    }


    public function updateDocuments(Request $request, $id)
    {
        $this->validate($request, [
            'user_id' => 'required|exists:users,id',
            'files_title' => 'required|string',
            'files_description' => 'required|string',
            'file' => 'sometimes|file|mimes:jpg,png,pdf|max:2048', // Optional file update.
        ]);

        $document = Document::findOrFail($id);

        // If a new file is provided, update it and delete the old file.
        if ($request->hasFile('file')) {
            $newFile = $request->file('file');
            $newFileUrl = $newFile->store('uploads', 'public');
            
            // Delete the old file.
            Storage::disk('public')->delete($document->file_url);

            $document->update([
                'user_id' => $request->user_id,
                'title' => $request->files_title,
                'body' => $request->files_description,
                'file_url' => $newFileUrl,
                'position' => $request->position ?? 0,
            ]);
        } else {
            // No new file provided, update the document with existing file.
            $document->update([
                'user_id' => $request->user_id,
                'title' => $request->files_title,
                'body' => $request->files_description,
                'position' => $request->position ?? 0,
            ]);
        }

        return response()->json($document);
    }

    public function destroyDocuments($id)
    {
        $document = Document::find($id);

        if (!$document) {
            return response()->json(['message' => 'Document not found'], 404);
        }

        // Delete the associated file from the 'uploads' directory in the 'public' disk.
        Storage::disk('public')->delete($document->file_url);

        // Delete the document from the database.
        $document->delete();

        return response()->json(['message' => 'Document deleted']);
    }

    public function updatePosition(Request $request)
    {
        $this->validate($request, [
            'documents' => 'required|array',
            'position' => 'required|integer',
        ]);

        $documents = $request->documents;

        foreach ($documents as $document) {
            Document::where('id', $document['id'])->update(['position' => $document['position']]);
        }

        return response()->json(['message' => 'Position updated!']);
    }

    // upload file and return file url
    public function uploadDocumentFile(Request $request)
    {
        $this->validate($request, [
            'file' => 'required|file|mimes:jpg,png,pdf|max:2048',
        ]);

        $file = $request->file('file');
        $fileUrl = $file->store('uploads/documents', 'public');

        return response()->json(['file_url' => $fileUrl]);
    }


}

我正在尝试上传文件。 期望返回文件路径

reactjs laravel file post
1个回答
0
投票

添加标头 'Skip-Content-Type': true,并删除 'formData' 参数对我的情况有帮助

示例:

uploadFile: builder.mutation({
  query: (body) => ({
    url: `/document/upload-file`,
    headers: {
      'Skip-Content-Type': true
    },
    method: "POST"
    body,
  }),
}),    
© www.soinside.com 2019 - 2024. All rights reserved.