我是 React 和 Fast Api 的新手。
我不太确定我做错了什么。
我有一个快速的 api 服务器,在发布请求时,用户令牌存储在 cookie 中。
我还有一个用 aiogram 编写的电报机器人。
我的想法是,在 aiogram 中,我向服务器发送请求,用户数据将通过解密的令牌写入数据库,并在反应中通过用户令牌获取此数据,以将某些值插入到模板中。为此,我在会话中使用 cookie 存储。
aiogramm 中的查询工作正常,所有内容都存储在数据库中,令牌被解密,但在我的 React 应用程序中,我收到 403 Forbidden 错误(
127.0.0.1:8000/generation/api/data/:1 Failed to load resource: the server responded with a status of 403 (Forbidden) RedSide1.tsx:46 Ошибка от сервера: Object config : {transitional: {…}, adapter: Array(3), transformRequest: Array(1), transformResponse: Array(1), timeout: 0, …} data : {detail: 'Токен не найден в куки.'} headers : AxiosHeaders {content-length: '54', content-type: 'application/json'} request : XMLHttpRequest {onreadystatechange: null, readyState: 4, timeout: 0, withCredentials: true, upload: XMLHttpRequestUpload, …} status : 403 statusText : "Forbidden" [[Prototype]] : Object)`)
你能告诉我错误的原因是什么吗???
fast_api_server/src/some_feature/router.py
from auth.jwt_handler import sign_jwt, decode_jwt
from auth.auth_bearer import JWTBearer
router = APIRouter(
prefix='/generation',
tags = ['ImageGeneration']
)
####### POST REQUESTS #######
@router.post("/generate_token/")
async def generate_token(user: UserIDSchema, response: Response):
token = await sign_jwt(user_id=user.user_id)
# Установка токена в HTTP-only cookie
response.set_cookie(
key="access_token",
value=token['access_token'],
httponly=True,
secure=False,
samesite="Lax"
)
return {
"status": "200",
"data": token,
"details": "Token is set in cookies"
}
@router.post('/api/add_data', dependencies=[Depends(JWTBearer())])
async def create_user_details_for_second_template(
new_template_info: Template2Param,
request: Request, # Получаем объект запроса для работы с куки
session: AsyncSession = Depends(get_async_session)
):
try:
# Извлекаем токен из куки
token = request.cookies.get("access_token")
print(token)
if not token:
raise HTTPException(status_code=403, detail="Токен не найден в куки.")
# Декодируем токен для получения user_id
decoded_token = decode_jwt(token)
if not decoded_token:
raise HTTPException(status_code=403, detail="Невалидный или истекший токен.")
user_id = decoded_token['user_id']
# Вставляем данные с user_id
stmt = insert(GenerationRequest).values(user_id=user_id, **new_template_info.model_dump())
await session.execute(stmt)
await session.commit()
return {
"status": "200",
"data": new_template_info,
"details": "All went correct and all data have been added"
}
except Exception as e:
raise HTTPException(status_code=400, detail=f"Ошибка: {str(e)}")
# Получаем данные из бд для второго шаблона
@router.get('/api/data', dependencies=[Depends(JWTBearer())])
async def get_all_data_for_second_template(request: Request, session: AsyncSession = Depends(get_async_session)):
try:
# Извлекаем токен из куки
token = request.cookies.get("access_token")
if not token:
raise HTTPException(status_code=403, detail="Токен не найден в куки.")
# Декодируем токен для получения user_id
decoded_token = decode_jwt(token)
if not decoded_token:
raise HTTPException(status_code=403, detail="Невалидный или истекший токен.")
user_id = decoded_token['user_id']
# Делаем запрос в базу данных с использованием user_id
query = select(GenerationRequestAll).where(GenerationRequestAll.user_id == user_id).order_by(GenerationRequestAll.id.desc()).limit(1)
result = await session.execute(query)
last_record = result.scalar_one_or_none()
if last_record:
return {
"status": "200",
"data": last_record,
"details": "Last record fetched successfully"
}
else:
return {
"status": "404",
"data": None,
"details": "No records found for the user"
}
except Exception as e:
raise HTTPException(status_code=400, detail=f"Error: {str(e)}")
tg_bot/some/some_handlers.py
# other code #
@staticmethod
async def generate_unic_token(tg_id: int, client: httpx.AsyncClient) -> None:
url_token = "link to post"
response = await client.post(url_token, json={"user_id": tg_id})
# Проверка ответа
if response.status_code == 200:
token_data = response.json()
print("Токен успешно получен:", token_data)
else:
print("Ошибка при получении токена:", response.status_code, response.text)
@staticmethod
async def post_request_to_api(data_dict, api_url, telegram_id, message: Message) -> None:
# Общие данные для отправки
data_for_server = {
"some_data":"some_data"
}
# Добавляем специфическое поле для 'all' типа
if 'all' in api_url:
data_for_server['restroom'] = data_dict['санузлы']
else:
data_for_server["ceiling"] = int(data_dict['потолок'])
async with httpx.AsyncClient() as client:
# Получаем токен и сохраняем куки в сессии
cookies = httpx.Cookies() # Создаем объект для хранения куки
client.cookies = cookies # Привязываем куки к клиенту
# Получаем токен и сохраняем его в куки
await Status.generate_unic_token(tg_id=telegram_id, client=client)
# Используем ту же сессию для отправки данных
response = await client.post(api_url, json=data_for_server)
# Проверка ответа
if response.status_code == 200:
print("Данные успешно добавлены:", response.json())
else:
print("Ошибка при добавлении данных:", response.status_code, response.text)
# Теперь делаем GET запрос, используя ту же сессию и куки
response = await client.get('link to get to check')
# Проверка ответа
if response.status_code == 200:
print("Данные успешно получены:", response.json())
else:
print("Ошибка при получении данных:", response.status_code, response.text)
# отправляет запрос на добавление на сервер
@router.message(State_Status.create_template)
async def handle_post_request(message: Message, state: FSMContext) -> None:
data = await state.get_data()
if data['choosing_template'] == 'Второй_шаблон':
api_url = "link to post"
else:
api_url = "link to post"
await Status.post_request_to_api(data_dict=data, api_url=api_url, telegram_id=message.from_user.id, message=message)
await state.clear()
frontend/src/pages/template.tsx
import React, { useEffect, useState } from "react";
import axios from "axios";
import { useLocation } from 'react-router-dom';
import FrameComponent1 from "../components/FrameComponent1";
import FrameComponent2 from "../components/FrameComponent2";
import Button1 from "../components/Button1";
import styles from "./RedSide1.module.css";
// Определяем интерфейс данных шаблона
interface TemplateData {
user_id: number;
above_building: string;
name_building: string;
below_building: string;
area: number; // Заменяем BigInteger на number
bedroom: number; // Заменяем BigInteger на number
floor: number; // Заменяем BigInteger на number
restroom: string; // Заменяем на string
price: number;
sales_price: number;
path: string[]; // Заменяем List на string[]
}
const RedSide1: React.FC = () => {
const [data, setData] = useState<TemplateData | null>(null);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchData = async () => {
try
const response = await axios.get('link to get', {
withCredentials: true,
headers: {
'Content-Type': 'application/json'
}
});
setData(response.data);
console.log(response.data)
} catch (error: unknown) {
// Приведение error к типу, который можно использовать
if (axios.isAxiosError(error)) {
// Если это ошибка axios
if (error.response) {
console.log('Ошибка от сервера:', error.response);
setError(`Ошибка: ${error.response.status} - ${error.response.data}`);
} else if (error.request) {
console.log('Проблема с запросом:', error.request);
setError('Ошибка: Сервер не ответил. Проверьте соединение.');
} else {
console.log('Ошибка при настройке запроса:', error.message);
setError(`Ошибка: ${error.message}`);
}
} else {
// Если ошибка не связана с axios
console.log('Неизвестная ошибка:', error);
setError('Произошла неизвестная ошибка.');
}
}
setLoading(false);
};
fetchData();
}, []);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
if (!data) return <div>No data available</div>;
/// other code///
fast_api_server/src/main.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddlewarefrom some_features.router import my_router
app = FastAPI(
title="Image Generation"
)
origins = [
# here are localhost and //127.0.0.1:5173 and //127.0.0.1:3000
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["GET", "POST", "OPTIONS", "DELETE", "PATCH", "PUT"],
allow_headers=["Content-Type", "Set-Cookie", "Access-Control-Allow-Headers", "Access-Control-Allow-Origin",
"Access-Control-Allow-Credential", "Authorization", "AxiosHeaders"],
)
app.include_router(some_router)
我可以提供更多代码。另外,如果我在代码生成中还有其他错误,你能指出来吗?
我更改了 CORS 并配置了 cookie,尝试通过数据库中的 telegram_id 获取某个用户的 React 服务器,但在这种情况下,有必要以某种方式将 id 传递到那里。所以我停止了将令牌存储在会话 cookie 中的选项。但这会导致 403 错误。 如果我在电报机器人中与发布请求相同的会话中发送获取请求,则获取请求有效,但它在反应中不起作用。你能帮我一下吗?
JWTBearer()
尝试在Authorization
标头中找到您的令牌,而当您将令牌存储在cookie中并在函数中执行验证时,这种情况不会发生,因此会发生错误,因为没有Authorization
标头并且没关系,因为您使用 cookie。
您可以删除 dependencies=[Depends(JWTBearer())]
,这样应该可以正常工作。