Отправка на сервер картинок React + Node
Хотел узнать, как можно попробовать загружать с ПК картинку и отправлять ее на какой-нибудь сервис с собственным API, после чего получать оттуда ссылку на картинку и сразу записывать ее в БД. У меня есть код из следующих файлов:
DragDrop.js
import React from "react"; import './DragDrop.css' import { useTranslation } from 'react-i18next'; import axios from "axios"; const sendDataToServer = async (imageUrl) => { try { const formData = new FormData(); formData.append("file", imageUrl); // Отправка данных на сервер const response = await axios.post("/api/uploadFile", formData, { headers: { "Content-Type": "multipart/form-data", }, }); if (response.status === 200) { console.log("Фотография успешно загружена"); } else { console.error("Ошибка при загрузке фотографии:", response.statusText); } } catch (error) { console.error("Ошибка при загрузке фотографии:", error.message); } }; // drag drop file component function DragDropFile() { const {t, i18n} = useTranslation() // drag state const [dragActive, setDragActive] = React.useState(false); // ref const inputRef = React.useRef(null); // handle drag events const handleDrag = function(e) { e.preventDefault(); e.stopPropagation(); if (e.type === 'dragenter' || e.type === 'dragover') { setDragActive(true); } else if (e.type === 'dragleave') { setDragActive(false); } }; // triggers when file is dropped const handleDrop = async function(e) { e.preventDefault(); setDragActive(false); if (e.target.files && e.target.files.length > 0) { handleFile(e.target.files); await sendDataToServer(e.dataTransfer.files[0]); } else { console.error('Нет загруженных файлов'); } }; function handleFile(files) { alert("Number of files: " + files.length); } // triggers when file is selected with click const handleChange = async function(e) { e.preventDefault(); if (e.target.files && e.target.files.length > 0) { console.log("Выбран файл:", e.target.files[0]); handleFile(e.target.files); await sendDataToServer(e.target.files[0]); } else { console.error('Нет загруженных файлов'); } }; // triggers the input when the button is clicked const onButtonClick = (e) => { e.preventDefault(); inputRef.current.click(); }; return ( <form className="element-animation" id="form-file-upload" onDragEnter={handleDrag} onSubmit={(e) => e.preventDefault()}> <input ref={inputRef} type="file" id="input-file-upload" multiple={true} onChange={handleChange} /> <label id="label-file-upload" htmlFor="input-file-upload" className={dragActive ? "drag-active" : "" }> <div> <p>{t('post.pic')}</p> <button className="upload-button" onClick={onButtonClick}>{t('post.picButton')}</button> </div> </label> { dragActive && <div id="drag-file-element" onDragEnter={(e) => e.preventDefault()} onDragLeave={(e) => e.preventDefault()} onDragOver={(e) => e.preventDefault()} onDrop={handleDrop}></div> } </form> ); }; export default DragDropFile;Form.js
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import Modal from "./Modal/Modal";
import { useInput } from "../hooks/use-form-validate";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faPersonCircleCheck } from "@fortawesome/free-solid-svg-icons";
import DragDropFile from "./DragNDrop/DragDrop.js";
import axios from "axios";
const sign = <FontAwesomeIcon icon={faPersonCircleCheck} size="2x" marginRight="10px" />;
function Form() {
const [modalActive, setModalActive] = useState(false);
const handleSubmit = async (imageUrl) => {
try {
const response = await axios.post("/api/addData", {
imageUrl: imageUrl, // Передаем URL загруженного изображения
title: title.value,
link: link.value,
text: text.value
});
if (response.status === 200) {
console.log("Данные успешно отправлены на сервер");
await sendDataToServer(imageUrl);
// setModalActive(true); // Показываем модальное окно об успешной отправке
} else {
console.error("Ошибка при отправке данных на сервер:", response.statusText);
}
} catch (error) {
console.error("Ошибка при отправке данных на сервер:", error.message);
}
};
const sendDataToServer = async (imageFile) => {
try {
const formData = new FormData();
formData.append("file", imageFile);
// Отправка изображения на сервер
const response = await axios.post("/api/uploadFile", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
if (response.status === 200) {
console.log("Фотография успешно загружена");
// Вызываем handleSubmit после успешной загрузки изображения
handleSubmit(response.data.imageUrl);
} else {
console.error("Ошибка при загрузке фотографии:", response.statusText);
}
} catch (error) {
console.error("Ошибка при загрузке фотографии:", error.message);
}
};
// const handleFilesDrop = async (files) => {
// try {
// const formData = new FormData();
// formData.append("file", files[0]);
// const response = await axios.post("/api/uploadPhoto", formData, {
// headers: {
// "Content-Type": "multipart/form-data"
// }
// });
// console.log("Ответ сервера:", response);
// if (response.status === 200) {
// console.log("Фотография успешно загружена");
//
// } else {
// console.error("Ошибка при загрузке фотографии:", response.statusText);
// }
// } catch (error) {
// console.error("Ошибка при загрузке фотографии:", error.message);
// }
// };
// Форма валидации
const { t } = useTranslation();
const title = useInput("", { isEmpty: true, minLength: 5 });
const link = useInput("", { isEmpty: true, minLength: 2 });
const pic = useInput("", { isEmpty: true, minLength: 1 });
const text = useInput("", { isEmpty: true, minLength: 2 });
return (
<form className="contact__form" onSubmit={handleSubmit}>
<div className="input__data">
<input
onBlur={title.onBlur}
value={title.value}
onChange={title.onChange}
className="name__input input form__control element-animation"
type="text"
placeholder={t("post.title")}
name="title"
required
/>
{title.isDirty && title.isEmpty && <div className="form__error">{t("error.empty")}</div>}
{title.isDirty && title.minLengthError && (
<div className="form__error">{t("error.length")}</div>
)}
</div>
<div className="input__data">
<input
onBlur={link.onBlur}
value={link.value}
onChange={link.onChange}
className="link__input input form__control element-animation"
type="text"
placeholder={t("post.link")}
name="link"
required
/>
{link.isDirty && link.isEmpty && <div className="form__error">{t("error.empty")}</div>}
{link.isDirty && link.minLengthError && (
<div className="form__error">{t("error.length")}</div>
)}
</div>
<DragDropFile sendDataToServer={sendDataToServer}/>
<div className="input__data">
<textarea
onBlur={text.onBlur}
value={text.value}
onChange={text.onChange}
className="form__textarea form__control element-animation"
name="text"
id="text"
placeholder={t("post.text")}
></textarea>
{text.isDirty && text.isEmpty && <div className="form__error">{t("error.empty")}</div>}
{text.isDirty && text.minLengthError && (
<div className="form__error">{t("error.length")}</div>
)}
</div>
<button
disabled={!title.inputValid || !link.inputValid || !text.inputValid}
className="form__btn form__control element-animation"
type="submit"
name="submit"
>
{t("post.button")}
</button>
<Modal active={modalActive} setActive={setModalActive}>
{sign}
<p>{t("contact.modalThanks")}</p>
<br />
<p>{t("contact.modalRequest")}</p>
</Modal>
</form>
);
}
export default Form;
server.js
// Импортируем необходимые зависимости const express = require('express'); const bodyParser = require('body-parser'); const mysql = require('mysql'); const cors = require('cors'); //const cloudinary = require('cloudinary').v2; const multer = require('multer'); import { v2 as cloudinary } from 'cloudinary'; cloudinary.config({ cloud_name: 'droi2nd1z', api_key: '598973367993171', api_secret: '***************************' }); const connection = mysql.createConnection({ host: 'localhost', user: 'root', password: '************', database: 'wtf_db' }); const upload = multer({ dest: 'uploads/' }); connection.connect((err) => { if (err) { console.error('Ошибка подключения к базе данных:', err); throw err; } console.log('Подключение к базе данных успешно установлено'); }); // Создаем экземпляр express const app = express(); // Используем middleware для обработки JSON данных app.use(bodyParser.json()); app.use(cors()); // Определяем маршрут для обработки POST запросов // app.post("/api/addData", upload.single('file'), async (req, res) => { // // Получаем данные из тела запроса // const { title, link, pic, text } = req.body; // // Выполняем операции с базой данных // const sql = `INSERT INTO past_orders_info (Header, link, photo, description) VALUES (?, ?, ?, ?)`; // connection.query(sql, [title, link, pic, text], (err, result) => { // if (err) { // console.error('Ошибка выполнения SQL запроса:', err); // res.status(500).send('Ошибка сервера'); // return; // } // console.log('Данные успешно добавлены в базу данных'); // res.status(200).send('Данные успешно добавлены в базу данных'); // }); // }); // app.post("/api/uploadFile", upload.single('file'), async (req, res) => { // if (!req.files || Object.keys(req.files).length === 0) { // return res.status(400).send('Нет загруженных файлов.'); // } //const file = req.files.file; try { const result = await cloudinary.uploader.upload(req.file.path); console.log('File uploaded to Cloudinary:', result); res.status(200).send(result.secure_url); } catch (error) { console.error('Error uploading file to Cloudinary:', error); res.status(500).send('Internal server error'); } // cloudinary.uploader.upload(file.tempFilePath, (error, result) => { // if (error) { // console.error('Ошибка при загрузке фотографии в Cloudinary:', error); // return res.status(500).send('Ошибка сервера'); // } console.log('Фотография успешно загружена в Cloudinary:', result); const imageUrl = result.secure_url; res.status(200).send(imageUrl); // }); // Устанавливаем порт, на котором будет работать сервер const port = process.env.PORT || 3000; // Запускаем сервер на выбранном порту app.listen(port, () => { console.log(`Сервер запущен на порту ${port}`); });
Как видно из кода, я пытался сделать что-то дельное с облачным сервисом cloudinary, который вряд ли даст что-то с ним сделать, хоть я и смог авторизоваться через GH-аккаунт с помощью VPN. Хочется понять, в правильном ли я вообще направлении иду и пользовался ли кто-нибудь эти облачным сервисом в последнее время? Какие есть аналоги подобного сервиса со своими API? Если будут какие-либо советы по правке кода и возможному решению моей задачи - буду безумно признателен!! Заранее извиняюсь за корявую табуляцию в коде...