diff --git a/app/web/admin/hooks/useRequestWorkspace.js b/app/web/admin/hooks/useRequestWorkspace.js index 59955aa..570a7bb 100644 --- a/app/web/admin/hooks/useRequestWorkspace.js +++ b/app/web/admin/hooks/useRequestWorkspace.js @@ -1,5 +1,22 @@ import { createRequestModalState } from "../shared/state.js"; +async function buildStorageUploadError(response, fallbackMessage) { + const base = String(fallbackMessage || "Не удалось загрузить файл в хранилище"); + const status = Number(response?.status || 0); + const statusText = String(response?.statusText || "").trim(); + let details = ""; + try { + details = String((await response.text()) || "").replace(/\s+/g, " ").trim(); + } catch (_) { + details = ""; + } + if (details.length > 180) details = details.slice(0, 180) + "..."; + const parts = []; + if (status > 0) parts.push("HTTP " + status + (statusText ? " " + statusText : "")); + if (details) parts.push(details); + return parts.length ? base + " (" + parts.join("; ") + ")" : base; +} + export function useRequestWorkspace(options) { const { useCallback, useRef, useState } = React; const opts = options || {}; @@ -247,7 +264,7 @@ export function useRequestWorkspace(options) { headers: { "Content-Type": mimeType }, body: file, }); - if (!putResp.ok) throw new Error("Не удалось загрузить файл в хранилище"); + if (!putResp.ok) throw new Error(await buildStorageUploadError(putResp, "Не удалось загрузить файл в хранилище")); await api("/api/admin/uploads/complete", { method: "POST", body: { @@ -413,7 +430,7 @@ export function useRequestWorkspace(options) { headers: { "Content-Type": mimeType }, body: file, }); - if (!putResp.ok) throw new Error("Не удалось загрузить файл в хранилище"); + if (!putResp.ok) throw new Error(await buildStorageUploadError(putResp, "Не удалось загрузить файл в хранилище")); await api("/api/admin/uploads/complete", { method: "POST", body: { diff --git a/app/web/client.jsx b/app/web/client.jsx index e516a43..0947839 100644 --- a/app/web/client.jsx +++ b/app/web/client.jsx @@ -370,6 +370,23 @@ import { detectAttachmentPreviewKind, fmtShortDateTime } from "./admin/shared/ut return data; }, []); + const buildStorageUploadError = useCallback(async (response, fallbackMessage) => { + const base = String(fallbackMessage || "Ошибка передачи файла в хранилище"); + const status = Number(response?.status || 0); + const statusText = String(response?.statusText || "").trim(); + let details = ""; + try { + details = String((await response.text()) || "").replace(/\s+/g, " ").trim(); + } catch (_) { + details = ""; + } + if (details.length > 180) details = details.slice(0, 180) + "..."; + const parts = []; + if (status > 0) parts.push("HTTP " + status + (statusText ? " " + statusText : "")); + if (details) parts.push(details); + return parts.length ? base + " (" + parts.join("; ") + ")" : base; + }, []); + const uploadPublicRequestAttachment = useCallback(async (file, extra = {}) => { const requestId = String(requestModal.requestId || "").trim(); if (!requestId) throw new Error("Не выбрана заявка"); @@ -394,7 +411,7 @@ import { detectAttachmentPreviewKind, fmtShortDateTime } from "./admin/shared/ut headers: { "Content-Type": mimeType }, body: file, }); - if (!putResponse.ok) throw new Error("Ошибка передачи файла в хранилище"); + if (!putResponse.ok) throw new Error(await buildStorageUploadError(putResponse, "Ошибка передачи файла в хранилище")); const completeData = await apiJson( "/api/public/uploads/complete", { @@ -413,7 +430,7 @@ import { detectAttachmentPreviewKind, fmtShortDateTime } from "./admin/shared/ut "Не удалось завершить загрузку файла" ); return completeData; - }, [apiJson, requestModal.requestId]); + }, [apiJson, buildStorageUploadError, requestModal.requestId]); const loadRequestWorkspace = useCallback( async (trackNumber, showLoading) => { diff --git a/frontend/nginx.conf b/frontend/nginx.conf index 5a81189..a2a5355 100644 --- a/frontend/nginx.conf +++ b/frontend/nginx.conf @@ -3,6 +3,7 @@ server { server_name _; server_tokens off; absolute_redirect off; + client_max_body_size 25m; root /usr/share/nginx/html; index index.html; @@ -94,6 +95,8 @@ server { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; + proxy_request_buffering off; + proxy_buffering off; } location /health { diff --git a/frontend/nginx.prod.conf b/frontend/nginx.prod.conf index d462173..eddf330 100644 --- a/frontend/nginx.prod.conf +++ b/frontend/nginx.prod.conf @@ -3,6 +3,7 @@ server { server_name _; server_tokens off; absolute_redirect off; + client_max_body_size 25m; root /usr/share/nginx/html; index index.html; @@ -94,6 +95,8 @@ server { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; + proxy_request_buffering off; + proxy_buffering off; proxy_ssl_server_name on; proxy_ssl_name minio; proxy_ssl_trusted_certificate /etc/nginx/minio-ca.crt;