Я пытаюсь загрузить файл из моего внешнего интерфейса React в серверную часть Flask-RESTful, но у меня возникла ошибка 422 (НЕОБРАБОТАННАЯ СУЩНОСТЬ).
Мои внутренние журналы показывают, что запрос POST достигает правильной конечной точки, но мои аргументы reqparse не проходят проверку.
Вот мой код:
/>Фронтенд (React ResumeUploader.jsx): я использую axios и FormData для отправки файла.
//ResumeUploader.jsx
import React, { useState } from 'react';
import axios from 'axios';
import { FiUploadCloud, FiAlertCircle } from 'react-icons/fi';
// This is the correct API endpoint
const UPLOAD_URL = 'http://localhost:5000/api/resume/upload';
const ResumeUploader = ({ setUploadMessage }) => {
const [file, setFile] = useState(null);
const [fileName, setFileName] = useState('No file selected');
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const handleFileChange = (e) => {
const selectedFile = e.target.files[0];
if (selectedFile) {
setFile(selectedFile);
setFileName(selectedFile.name);
setError('');
setUploadMessage('');
}
};
const handleSubmit = async (e) => {
e.preventDefault();
if (!file) {
setError('Please select a file to upload.');
return;
}
setLoading(true);
setError('');
setUploadMessage('');
const formData = new FormData();
formData.append('resume', file);
const token = localStorage.getItem('token');
try {
// This is the 100% correct, bug-free request
const res = await axios.post(UPLOAD_URL, formData, {
headers: {
// NO 'Content-Type' header here. This is correct.
'Authorization': `Bearer ${token}`
}
});
setUploadMessage(res.data.message);
setFile(null);
setFileName('No file selected');
} catch (err) {
setError(err.response?.data?.message || err.message || 'Upload failed. Please try again.');
} finally {
setLoading(false);
}
};
return (
{fileName}
Click to select a file (PDF or DOCX)
{loading ? 'Uploading...' : 'Upload Resume'}
{error && (
{error}
)}
);
};
export default ResumeUploader;
Бэкэнд (Flask summary_routes.py): я использую Flask-RESTful и reqparse для перехвата файла.
//resume_routes.py
from flask_restful import Resource, reqparse
from flask_jwt_extended import jwt_required, get_jwt_identity
from werkzeug.datastructures import FileStorage
from extensions import mongo
from utils.pdf_extractor import extract_text_from_file
from services.resume_parser import parse_resume
from services.scoring_engine import calculate_suitability_score
from models.user_model import User
import os
import re
# Create a directory for uploads
UPLOAD_FOLDER = 'uploads'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
upload_parser = reqparse.RequestParser()
upload_parser.add_argument('resume', type=FileStorage, location='files', required=True, help="Resume file is required")
analyze_parser = reqparse.RequestParser()
analyze_parser.add_argument('job_description', type=str, required=True, help="Job description is required")
class ResumeUpload(Resource):
@jwt_required()
def post(self):
data = upload_parser.parse_args()
resume_file = data['resume']
identity = get_jwt_identity()
user = User.find_by_email(identity['email'])
if not user:
return {'message': 'User not found'}, 404
filename = re.sub(r'[^a-zA-Z0-9._-]', '_', resume_file.filename)
file_path = os.path.join(UPLOAD_FOLDER, f"{user['_id']}_{filename}")
try:
resume_file.save(file_path)
text = extract_text_from_file(file_path)
if text is None:
return {'message': 'Unsupported file type or error reading file'}, 400
parsed_data = parse_resume(text)
mongo.db.resumes.update_one(
{'user_id': user['_id']},
{'$set': {
'user_id': user['_id'],
'filename': filename,
'text': parsed_data['full_text'],
'parsed': parsed_data
}},
upsert=True
)
except Exception as e:
return {'message': f"An error occurred: {str(e)}"}, 500
finally:
if os.path.exists(file_path):
os.remove(file_path)
return {'message': 'Resume uploaded and parsed successfully', 'data': parsed_data}, 201
class ResumeAnalyze(Resource):
@jwt_required()
def post(self):
identity = get_jwt_identity()
if identity['role'] != 'recruiter':
return {'message': 'Access forbidden: Recruiters only'}, 403
data = analyze_parser.parse_args()
job_description = data['job_description']
candidates = []
for resume in mongo.db.resumes.find():
resume_text = resume.get('text', '')
parsed_data = resume.get('parsed', {})
score, matched, missing = calculate_suitability_score(resume_text, job_description)
candidates.append({
'name': parsed_data.get('name', 'Unknown'),
'email': parsed_data.get('email', 'Unknown'),
'score': score,
'matched_skills': matched,
'missing_skills': missing
})
ranked_candidates = sorted(candidates, key=lambda x: x['score'], reverse=True)
return {'message': 'Analysis complete', 'results': ranked_candidates}, 200
def init_resume_routes(api):
api.add_resource(ResumeUpload, '/resume/upload')
api.add_resource(ResumeAnalyze, '/resume/analyze')
Подробнее здесь: https://stackoverflow.com/questions/798 ... ble-entity
Загрузка файла React/Axios в Flask-RESTful дает 422 необрабатываемых объекта ⇐ Python
Программы на Python
1766951029
Anonymous
Я пытаюсь загрузить файл из моего внешнего интерфейса React в серверную часть Flask-RESTful, но у меня возникла ошибка 422 (НЕОБРАБОТАННАЯ СУЩНОСТЬ).
Мои внутренние журналы показывают, что запрос POST достигает правильной конечной точки, но мои аргументы reqparse не проходят проверку.
Вот мой код:
/>[b]Фронтенд (React ResumeUploader.jsx):[/b] я использую axios и FormData для отправки файла.
//ResumeUploader.jsx
import React, { useState } from 'react';
import axios from 'axios';
import { FiUploadCloud, FiAlertCircle } from 'react-icons/fi';
// This is the correct API endpoint
const UPLOAD_URL = 'http://localhost:5000/api/resume/upload';
const ResumeUploader = ({ setUploadMessage }) => {
const [file, setFile] = useState(null);
const [fileName, setFileName] = useState('No file selected');
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const handleFileChange = (e) => {
const selectedFile = e.target.files[0];
if (selectedFile) {
setFile(selectedFile);
setFileName(selectedFile.name);
setError('');
setUploadMessage('');
}
};
const handleSubmit = async (e) => {
e.preventDefault();
if (!file) {
setError('Please select a file to upload.');
return;
}
setLoading(true);
setError('');
setUploadMessage('');
const formData = new FormData();
formData.append('resume', file);
const token = localStorage.getItem('token');
try {
// This is the 100% correct, bug-free request
const res = await axios.post(UPLOAD_URL, formData, {
headers: {
// NO 'Content-Type' header here. This is correct.
'Authorization': `Bearer ${token}`
}
});
setUploadMessage(res.data.message);
setFile(null);
setFileName('No file selected');
} catch (err) {
setError(err.response?.data?.message || err.message || 'Upload failed. Please try again.');
} finally {
setLoading(false);
}
};
return (
{fileName}
Click to select a file (PDF or DOCX)
{loading ? 'Uploading...' : 'Upload Resume'}
{error && (
{error}
)}
);
};
export default ResumeUploader;
Бэкэнд (Flask summary_routes.py): я использую Flask-RESTful и reqparse для перехвата файла.
//resume_routes.py
from flask_restful import Resource, reqparse
from flask_jwt_extended import jwt_required, get_jwt_identity
from werkzeug.datastructures import FileStorage
from extensions import mongo
from utils.pdf_extractor import extract_text_from_file
from services.resume_parser import parse_resume
from services.scoring_engine import calculate_suitability_score
from models.user_model import User
import os
import re
# Create a directory for uploads
UPLOAD_FOLDER = 'uploads'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
upload_parser = reqparse.RequestParser()
upload_parser.add_argument('resume', type=FileStorage, location='files', required=True, help="Resume file is required")
analyze_parser = reqparse.RequestParser()
analyze_parser.add_argument('job_description', type=str, required=True, help="Job description is required")
class ResumeUpload(Resource):
@jwt_required()
def post(self):
data = upload_parser.parse_args()
resume_file = data['resume']
identity = get_jwt_identity()
user = User.find_by_email(identity['email'])
if not user:
return {'message': 'User not found'}, 404
filename = re.sub(r'[^a-zA-Z0-9._-]', '_', resume_file.filename)
file_path = os.path.join(UPLOAD_FOLDER, f"{user['_id']}_{filename}")
try:
resume_file.save(file_path)
text = extract_text_from_file(file_path)
if text is None:
return {'message': 'Unsupported file type or error reading file'}, 400
parsed_data = parse_resume(text)
mongo.db.resumes.update_one(
{'user_id': user['_id']},
{'$set': {
'user_id': user['_id'],
'filename': filename,
'text': parsed_data['full_text'],
'parsed': parsed_data
}},
upsert=True
)
except Exception as e:
return {'message': f"An error occurred: {str(e)}"}, 500
finally:
if os.path.exists(file_path):
os.remove(file_path)
return {'message': 'Resume uploaded and parsed successfully', 'data': parsed_data}, 201
class ResumeAnalyze(Resource):
@jwt_required()
def post(self):
identity = get_jwt_identity()
if identity['role'] != 'recruiter':
return {'message': 'Access forbidden: Recruiters only'}, 403
data = analyze_parser.parse_args()
job_description = data['job_description']
candidates = []
for resume in mongo.db.resumes.find():
resume_text = resume.get('text', '')
parsed_data = resume.get('parsed', {})
score, matched, missing = calculate_suitability_score(resume_text, job_description)
candidates.append({
'name': parsed_data.get('name', 'Unknown'),
'email': parsed_data.get('email', 'Unknown'),
'score': score,
'matched_skills': matched,
'missing_skills': missing
})
ranked_candidates = sorted(candidates, key=lambda x: x['score'], reverse=True)
return {'message': 'Analysis complete', 'results': ranked_candidates}, 200
def init_resume_routes(api):
api.add_resource(ResumeUpload, '/resume/upload')
api.add_resource(ResumeAnalyze, '/resume/analyze')
Подробнее здесь: [url]https://stackoverflow.com/questions/79816319/react-axios-file-upload-to-flask-restful-gives-422-unprocessable-entity[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия