Я продолжаю получать ошибку 422 Unprocessable Entity
со следующими отсутствующими полями:
{"detail":[{"type":"missing","loc":["body","username"],"msg":"Field required","input":null},{"type":"missing","loc":["body","password"],"msg":"Field required","input":null}]}
Я перепробовал все возможное, но ошибка остается.
Это мой код интерфейса:
const Login = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const navigate = useNavigate();
const handleLogin = async (e) => {
e.preventDefault();
const formData = new URLSearchParams();
formData.append('username', email); // Assuming the backend expects 'username'
formData.append('password', password);
try {
const response = await fetch('http://localhost:8000/token', {
method: 'POST',
body: formData,
});
if (!response.ok) {
throw new Error('Login failed');
}
и это бэкэнд:
@fastapi_router.post("/token", response_model=Token)
async def login_for_access_token(
username: Annotated[str, Form()],
password: Annotated[str, Form()],
db: AsyncSession = Depends(database.get_db)
):
user = await auth.authenticate_user(db, username, password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail = "Incorrect username or password",
headers = {"WWW-Authenticate": "Bearer"},
)
access_token_expires = timedelta(minutes=envs.access_token_expire_minutes)
access_token = auth.create_access_token(
data = {"sub": user.username}, expires_delta=access_token_expires
)
logger.info(f"Access Token: {access_token}")
return {"access_token": access_token, "token_type": "bearer"}
Любая помощь будет оценена по достоинству.
Привет @Chris, спасибо за ответы. Я пробовал все, даже с FormData на стороне js, я пробовал аннотированные и неаннотированные параметры функции для бэкэнда: fastapi.tiangolo.com/tutorial/request-forms/#__tabbed_1_3 Я пробовал разные заголовки и типы контента. Ни при каком подходе это не работает, я в ярости.
Вот рабочий пример того, как отправить данные Form
на серверную часть FastAPI с помощью API JavaScript Fetch во внешнем интерфейсе. Ответы по теме, где вы можете прочитать больше об используемых ниже методах, можно найти здесь , а также здесь и здесь.
Обратите внимание: при ожидании полей username
и password
в качестве данных формы можно альтернативно использовать класс зависимостей OAuth2PasswordRequestForm , предлагаемый FastAPI. Похожие ответы по этому классу можно увидеть здесь , а также здесь , здесь и здесь.
app.py
from fastapi import FastAPI, Form, Request
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
app = FastAPI()
templates = Jinja2Templates(directory = "templates")
@app.post("/submit")
def submit(username: str = Form(...), password: str = Form(...)):
return {"username": username, "password": password}
@app.get("/", response_class=HTMLResponse)
def main(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
шаблоны/index.html
<!DOCTYPE html>
<html>
<body>
<input type = "button" value = "Submit" onclick = "send()">
<p id = "resp"></p>
<script>
function send() {
var resp = document.getElementById("resp");
var formData = new FormData();
formData.append("username", "test");
formData.append("password", "pass");
fetch('/submit', {
method: 'POST',
body: formData,
})
.then(response => response.json())
.then(data => {
resp.innerHTML = JSON.stringify(data); // data is a JSON object
})
.catch(error => {
console.error(error);
});
}
</script>
</body>
</html>
Этот тестовый шаблон помог мне выполнить отладку и найти причину моей проблемы. Я использовал специальное промежуточное программное обеспечение fastapi для регистрации входящего запроса, и по какой-то причине оно сработало, когда я удалил это промежуточное программное обеспечение. Я предполагаю, что это меняло тип контента данных запроса.
Это также может произойти, если вы используете Axios в реакции js и в файле axiosConfig.js вы случайно установили определенный тип содержимого заголовка, который используется для любого запроса при импорте axiosInstance, инициализированного в axiosConfig.js. Это может остаться незамеченным
Отвечает ли это на ваш вопрос (пожалуйста, посмотрите вариант 2)?