Błąd ERRUPLOADSTREAMREWINDNOT_SUPPORTED to problem, który najczęściej występuje w aplikacjach Node.js podczas próby ponownego wysłania danych ze strumienia, który nie obsługuje operacji przewijania wstecz. Jest to szczególnie powszechne przy pracy z bibliotekami do obsługi żądań HTTP, takimi jak Axios, Request lub Got.
Czym jest ten błąd?
ERRUPLOADSTREAMREWINDNOT_SUPPORTED pojawia się, gdy aplikacja próbuje automatycznie ponowić nieudane żądanie HTTP zawierające strumień danych (stream), który został już częściowo lub całkowicie odczytany. Ponieważ strumienie w Node.js są jednorazowe i nie można ich „cofnąć” do początku, próba ponownego wysłania kończy się błędem.
Typowe scenariusze wystąpienia –
- Przesyłanie plików przez formularze multipart/form-data
- Automatyczne ponowne próby żądań HTTP przy błędach sieciowych
- Przekierowania HTTP (301, 302) podczas wysyłania danych
- Proxy i middleware przetwarzające strumienie danych
Dla Web Deweloperów
Przyczyny techniczne
Główne przyczyny tego błędu to:
Wykorzystanie strumieni Node.js w żądaniach HTTP – obiekty typu fs.createReadStream() lub inne strumienie danych nie mogą być ponownie odczytane po pierwszym użyciu.
Automatyczne mechanizmy retry – biblioteki HTTP często próbują automatycznie ponawiać nieudane żądania, co powoduje konflikt ze strumieniami.
Przekierowania HTTP – gdy serwer odpowiada kodem przekierowania podczas przesyłania strumienia, klient musi wysłać dane ponownie, co jest niemożliwe.
Rozwiązania dla Node.js i Axios
Rozwiązanie 1 – Wyłączenie automatycznych powtórzeń
const axios = require('axios'); const fs = require('fs'); const formData = new FormData(); formData.append('file', fs.createReadStream('plik.pdf')); axios.post('https://example.com/upload', formData, { maxRedirects: 0, // Wyłącz przekierowania maxContentLength: Infinity, maxBodyLength: Infinity, headers: { ...formData.getHeaders() } }) .catch(error => { console.error('Błąd:', error.message); });
Rozwiązanie 2 – Użycie bufora zamiast strumienia
const axios = require('axios'); const fs = require('fs'); // Wczytaj cały plik do pamięci const fileBuffer = fs.readFileSync('plik.pdf'); const formData = new FormData(); formData.append('file', fileBuffer, 'plik.pdf'); axios.post('https://example.com/upload', formData, { headers: { ...formData.getHeaders() } });
Rozwiązanie 3 – Implementacja własnego mechanizmu retry
const axios = require('axios'); const fs = require('fs'); async function uploadWithRetry(url, filePath, maxRetries = 3) { for (let attempt = 0; attempt < maxRetries; attempt++) { try { const formData = new FormData(); // Twórz nowy strumień przy każdej próbie formData.append('file', fs.createReadStream(filePath)); const response = await axios.post(url, formData, { maxRedirects: 0, headers: { ...formData.getHeaders() } }); return response.data; } catch (error) { if (attempt === maxRetries - 1) throw error; console.log(`Próba ${attempt + 1} nieudana, ponawiam...`); await new Promise(resolve => setTimeout(resolve, 1000 * (attempt + 1))); } } }
Rozwiązania dla innych bibliotek HTTP
Fetch API
const fs = require('fs'); const FormData = require('form-data'); const formData = new FormData(); const fileBuffer = fs.readFileSync('plik.pdf'); formData.append('file', fileBuffer, 'plik.pdf'); fetch('https://example.com/upload', { method: 'POST', body: formData, redirect: 'manual' // Wyłącz automatyczne przekierowania }) .then(response => response.json()) .then(data => console.log(data));
Request (przestarzałe, ale wciąż używane)
const request = require('request'); const fs = require('fs'); const formData = { file: { value: fs.readFileSync('plik.pdf'), options: { filename: 'plik.pdf', contentType: 'application/pdf' } } }; request.post({ url: 'https://example.com/upload', formData: formData, followRedirect: false }, (err, response, body) => { if (err) console.error(err); console.log(body); });
Konfiguracja po stronie serwera
Jeśli kontrolujesz serwer, możesz zapobiec problemowi poprzez:
Unikanie przekierowań podczas uploadu – upewnij się, że endpoint przyjmujący pliki nie wykonuje przekierowań HTTP.
// Express.js app.post('/upload', (req, res) => { // Nie używaj res.redirect() po otrzymaniu pliku // Zamiast tego zwróć odpowiedź bezpośrednio res.status(200).json({ success: true }); });
Zwiększenie limitów timeoutów – daj więcej czasu na przesłanie większych plików.
app.use(express.json({ limit: '50mb' })); app.use(express.urlencoded({ limit: '50mb', extended: true }));
Best Practices
Walidacja po stronie klienta – sprawdź rozmiar i typ pliku przed wysłaniem, aby uniknąć niepotrzebnych przesyłań.
Używaj buforów dla małych plików – pliki poniżej 10-20 MB można bezpiecznie wczytać do pamięci.
Implementuj chunked upload – dla dużych plików podziel je na mniejsze części i wysyłaj sekwencyjnie.
async function uploadInChunks(filePath, chunkSize = 1024 * 1024) { const fileSize = fs.statSync(filePath).size; const chunks = Math.ceil(fileSize / chunkSize); for (let i = 0; i < chunks; i++) { const start = i * chunkSize; const end = Math.min(start + chunkSize, fileSize); const chunk = fs.readFileSync(filePath, { start, end }); await axios.post('https://example.com/upload/chunk', { chunk: chunk.toString('base64'), index: i, total: chunks }); } }
Dla Webmasterów
Diagnostyka problemu
Krok 1: Sprawdź logi serwera
Poszukaj wpisów zawierających:
- ERRUPLOADSTREAMREWINDNOT_SUPPORTED
- Kody błędów HTTP 301, 302, 307, 308
- Timeouty podczas przesyłania plików
Krok 2: Zidentyfikuj problematyczne endpointy
Sprawdź, które ścieżki URL powodują problem:
- Endpointy przyjmujące pliki
- Formularze z enctype=”multipart/form-data”
- API przyjmujące duże payloady
Krok 3: Testuj środowisko
Użyj narzędzi takich jak Postman lub curl do testowania:
curl -X POST -F "[email protected]" https://example.com/upload -v
Szybkie naprawy bez zmiany kodu
Wyłącz przekierowania na poziomie serwera
Dla Apache (.htaccess):
# Usuń lub zakomentuj reguły przekierowujące dla endpointów upload # RewriteRule ^upload/ https://example.com/upload/ [R=301,L]
Dla Nginx:
location /upload { # Usuń dyrektywy return 301/302 # return 301 https://example.com$request_uri; # Zamiast tego użyj proxy_pass bez przekierowań proxy_pass http://backend; }
Zwiększ limity czasowe
Apache:
Timeout 600 ProxyTimeout 600
Nginx:
client_body_timeout 600s; proxy_read_timeout 600s;
Monitoring i prewencja
Skonfiguruj alerty – monitoruj logi pod kątem wystąpienia tego błędu i otrzymuj powiadomienia.
Dokumentuj endpointy – utrzymuj dokumentację API z informacjami o limitach rozmiaru plików i formatach akceptowanych danych.
Regularne testy – przeprowadzaj testy przesyłania plików różnych rozmiarów w środowisku testowym.
Dla Użytkowników Końcowych
Objawy problemu
Możesz doświadczyć tego błędu, gdy:
- Przesyłanie pliku zatrzymuje się w połowie
- Pojawia się komunikat o błędzie podczas uploadu
- Strona przekierowuje podczas przesyłania pliku
- Upload działa dla małych plików, ale nie dla dużych
Proste rozwiązania
Odśwież stronę i spróbuj ponownie – czasami problem jest tymczasowy i wynika z problemów sieciowych.
Sprawdź połączenie internetowe – niestabilne połączenie może powodować przerwy w przesyłaniu.
Zmniejsz rozmiar pliku – jeśli przesyłasz bardzo duży plik:
- Skompresuj go (ZIP, RAR)
- Zmniejsz rozdzielczość obrazów
- Użyj bardziej efektywnych formatów (np. JPEG zamiast PNG dla zdjęć)
Użyj innej przeglądarki – niektóre przeglądarki lepiej radzą sobie z przesyłaniem dużych plików:
- Chrome/Edge – zazwyczaj najbardziej stabilne
- Firefox – dobra alternatywa
- Safari – może mieć problemy z bardzo dużymi plikami
Wyczyść cache przeglądarki – stare dane mogą powodować konflikty:
- Chrome/Edge: Ctrl+Shift+Del → wybierz „Cached images and files”
- Firefox: Ctrl+Shift+Del → wybierz „Cache”
- Safari: Preferences → Privacy → Manage Website Data → Remove All
Wyłącz rozszerzenia przeglądarki – niektóre rozszerzenia mogą ingerować w proces przesyłania:
- Blokery reklam
- VPN
- Menedżery pobierania
Gdy nic nie działa
Skontaktuj się z administratorem strony – zgłoś problem podając:
- Dokładny komunikat błędu
- Rozmiar pliku, który próbujesz przesłać
- Przeglądarkę i system operacyjny
- Czy problem występuje zawsze, czy sporadycznie
Użyj alternatywnych metod – jeśli to możliwe:
- Prześlij plik przez usługi zewnętrzne (Google Drive, Dropbox) i udostępnij link
- Podziel plik na mniejsze części
- Skorzystaj z dedykowanych aplikacji do przesyłania plików
Najczęstsze pytania
Czy to problem po mojej stronie?
Zazwyczaj nie. Ten błąd najczęściej wynika z konfiguracji serwera lub kodu aplikacji. Jednak problemy z siecią mogą go potęgować.
Czy mogę stracić dane?
Nie, błąd występuje podczas przesyłania, więc oryginalne pliki na Twoim komputerze pozostają nietknięte.
Dlaczego działa dla małych plików?
Małe pliki przesyłają się szybko, zanim wystąpią problemy z przekierowaniami lub timeoutami. Duże pliki są bardziej podatne na przerwania.
Czy to bezpieczne próbować ponownie?
Tak, możesz bezpiecznie próbować przesłać plik wielokrotnie. Każda próba jest niezależna.
Podsumowanie
Błąd ERRUPLOADSTREAMREWINDNOT_SUPPORTED to techniczny problem związany z obsługą strumieni danych w Node.js. Dla deweloperów kluczowe jest używanie buforów zamiast strumieni lub implementacja właściwego mechanizmu ponawiania prób. Webmasterzy powinni skupić się na eliminacji przekierowań i zwiększeniu limitów czasowych. Użytkownicy końcowi mogą rozwiązać problem przez odświeżenie strony, użycie innej przeglądarki lub zmniejszenie rozmiaru plików.

