When I send a fetch request from the frontend server (React) to the backend server (FastAPI), an error occurs:
localhost/:1 Access to fetch at 'http://localhost:8000/predict/' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Environment:
Frontend:
import React from "react";
import { useForm } from "react-hook-form";
import { useMutation } from "@tanstack/react-query";
interface FormSchema {
mean_radius: number;
mean_texture: number;
mean_perimeter: number;
mean_area: number;
}
interface PredictionResponse {
prediction: number;
}
const Frontend = () => {
const { register, handleSubmit } = useForm<FormSchema>({
defaultValues: {
mean_radius: 0,
mean_texture: 0,
mean_perimeter: 0,
mean_area: 0,
},
});
// Mutation for sending data to the backend
const mutation = useMutation<PredictionResponse, Error, FormSchema>({
mutationFn: async (formData: FormSchema) => {
const response = await fetch("http://localhost:8000/predict/", {
method: "POST",
credentials: 'include',
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(formData),
});
if (!response.ok) {
throw new Error("Failed to fetch");
}
return response.json();
}
});
const onSubmit = (data: FormSchema) => {
mutation.mutate(data);
};
return (
<div>
<h1>React + FastAPI Example</h1>
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label>Mean Radius:</label>
<input type="number" {...register("mean_radius")} />
</div>
<div>
<label>Mean Texture:</label>
<input type="number" {...register("mean_texture")} />
</div>
<div>
<label>Mean Perimeter:</label>
<input type="number" {...register("mean_perimeter")} />
</div>
<div>
<label>Mean Area:</label>
<input type="number" {...register("mean_area")} />
</div>
<button type="submit">Predict</button>
</form>
{/* Display loading, error, or success states */}
{mutation.isError && (
<p>Error occurred: {(mutation.error as Error).message}</p>
)}
{mutation.isSuccess && (
<p>Prediction Result: {mutation.data?.prediction}</p>
)}
</div>
);
};
export default Frontend;
Backend:
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
app = FastAPI()
# Define the data schema
class TestData(BaseModel):
mean_radius: float
mean_texture: float
mean_perimeter: float
mean_area: float
# Configure CORS settings
origins = [
"http://localhost:3000", # React frontend
"http://127.0.0.1:3000"
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins, # Allow requests from specific origins
allow_credentials=True, # Allow cookies and credentials if needed
allow_methods=["*"], # Allow all HTTP methods (GET, POST, etc.)
allow_headers=["*"], # Allow all headers
)
@app.post("/predict/")
def do_predict(data: TestData):
# Example processing logic (replace with actual logic)
result = data.mean_radius + data.mean_texture + data.mean_perimeter + data.mean_area
return {"prediction": result}
How I started servers:
npm start
uvicorn maintest:app --reload --host 0.0.0.0 --port 8000
I checked:
python log
INFO: Stopping reloader process [64148]
PS E:\workspace\Python\tmp\front-back-end\backend> uvicorn maintest:app --reload --host 0.0.0.0 --port 8000
INFO: Will watch for changes in these directories: ['E:\\workspace\\Python\\tmp\\front-back-end\\backend']
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO: Started reloader process [33768] using WatchFiles
ERROR: Error loading ASGI app. Attribute "app" not found in module "maintest".
WARNING: WatchFiles detected changes in 'maintest.py'. Reloading...
INFO: Started server process [73580]
INFO: Waiting for application startup.
INFO: Application startup complete.
Change the port number in React code and uvicorn command. Surprisingly, it worked. Perhaps after killning the uvicorn by Ctrl+C, zombie processes remained behind the console.