Улучшена загрузка метаданных wishlist
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 56s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 56s
This commit is contained in:
@@ -9974,49 +9974,85 @@ func (a *App) extractLinkMetadataHandler(w http.ResponseWriter, r *http.Request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
log.Printf("Error decoding metadata request body: %v", err)
|
||||||
sendErrorWithCORS(w, "Invalid request body", http.StatusBadRequest)
|
sendErrorWithCORS(w, "Invalid request body", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.URL == "" {
|
if req.URL == "" {
|
||||||
|
log.Printf("Empty URL in metadata request")
|
||||||
sendErrorWithCORS(w, "URL is required", http.StatusBadRequest)
|
sendErrorWithCORS(w, "URL is required", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("Extracting metadata for URL: %s", req.URL)
|
||||||
|
|
||||||
// Валидация URL
|
// Валидация URL
|
||||||
parsedURL, err := url.Parse(req.URL)
|
parsedURL, err := url.Parse(req.URL)
|
||||||
if err != nil || parsedURL.Scheme == "" || parsedURL.Host == "" {
|
if err != nil || parsedURL.Scheme == "" || parsedURL.Host == "" {
|
||||||
|
log.Printf("Invalid URL format: %s, error: %v", req.URL, err)
|
||||||
sendErrorWithCORS(w, "Invalid URL", http.StatusBadRequest)
|
sendErrorWithCORS(w, "Invalid URL", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTP клиент с таймаутом
|
// HTTP клиент с увеличенным таймаутом и поддержкой редиректов
|
||||||
|
// Используем Transport с настройками для лучшей совместимости
|
||||||
|
transport := &http.Transport{
|
||||||
|
DisableKeepAlives: false,
|
||||||
|
MaxIdleConns: 10,
|
||||||
|
IdleConnTimeout: 90 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
Timeout: 10 * time.Second,
|
Timeout: 30 * time.Second, // Увеличиваем таймаут до 30 секунд
|
||||||
|
Transport: transport,
|
||||||
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||||
|
// Разрешаем до 10 редиректов
|
||||||
|
if len(via) >= 10 {
|
||||||
|
return fmt.Errorf("stopped after 10 redirects")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
httpReq, err := http.NewRequest("GET", req.URL, nil)
|
httpReq, err := http.NewRequest("GET", req.URL, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error creating request: %v", err)
|
log.Printf("Error creating request for URL %s: %v", req.URL, err)
|
||||||
sendErrorWithCORS(w, "Error creating request", http.StatusInternalServerError)
|
sendErrorWithCORS(w, "Error creating request", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Устанавливаем User-Agent (некоторые сайты блокируют запросы без него)
|
// Устанавливаем заголовки, имитирующие реальный браузер Chrome
|
||||||
httpReq.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
|
httpReq.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
|
||||||
httpReq.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
|
httpReq.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7")
|
||||||
httpReq.Header.Set("Accept-Language", "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7")
|
httpReq.Header.Set("Accept-Language", "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7")
|
||||||
|
httpReq.Header.Set("Accept-Encoding", "gzip, deflate, br")
|
||||||
|
httpReq.Header.Set("Connection", "keep-alive")
|
||||||
|
httpReq.Header.Set("Upgrade-Insecure-Requests", "1")
|
||||||
|
httpReq.Header.Set("Sec-Fetch-Dest", "document")
|
||||||
|
httpReq.Header.Set("Sec-Fetch-Mode", "navigate")
|
||||||
|
httpReq.Header.Set("Sec-Fetch-Site", "none")
|
||||||
|
httpReq.Header.Set("Sec-Fetch-User", "?1")
|
||||||
|
httpReq.Header.Set("Cache-Control", "max-age=0")
|
||||||
|
httpReq.Header.Set("DNT", "1")
|
||||||
|
|
||||||
resp, err := client.Do(httpReq)
|
resp, err := client.Do(httpReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error fetching URL: %v", err)
|
log.Printf("Error fetching URL %s: %v", req.URL, err)
|
||||||
sendErrorWithCORS(w, fmt.Sprintf("Error fetching URL: %v", err), http.StatusBadRequest)
|
sendErrorWithCORS(w, fmt.Sprintf("Error fetching URL: %v", err), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
// Логируем статус код для отладки
|
||||||
sendErrorWithCORS(w, fmt.Sprintf("HTTP %d", resp.StatusCode), http.StatusBadRequest)
|
log.Printf("Fetched URL %s, status: %d", req.URL, resp.StatusCode)
|
||||||
|
|
||||||
|
// Принимаем успешные статусы (200-299) и некоторые редиректы, которые могут содержать контент
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||||
|
// Для некоторых сайтов можно попробовать прочитать тело даже при не-200 статусе
|
||||||
|
// Но для большинства случаев это ошибка
|
||||||
|
log.Printf("Non-OK status code for URL %s: %d", req.URL, resp.StatusCode)
|
||||||
|
sendErrorWithCORS(w, fmt.Sprintf("HTTP %d: %s", resp.StatusCode, resp.Status), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "play-life-web",
|
"name": "play-life-web",
|
||||||
"version": "3.10.6",
|
"version": "3.10.7",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -220,11 +220,31 @@ function WishlistForm({ onNavigate, wishlistId, editConditionIndex }) {
|
|||||||
setToastMessage({ text: 'Не удалось найти информацию на странице', type: 'warning' })
|
setToastMessage({ text: 'Не удалось найти информацию на странице', type: 'warning' })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setToastMessage({ text: 'Не удалось загрузить информацию', type: 'error' })
|
// Пытаемся получить детальное сообщение об ошибке
|
||||||
|
let errorMessage = 'Не удалось загрузить информацию'
|
||||||
|
try {
|
||||||
|
const errorData = await response.json()
|
||||||
|
errorMessage = errorData.message || errorData.error || errorMessage
|
||||||
|
} catch (e) {
|
||||||
|
const text = await response.text().catch(() => '')
|
||||||
|
if (text) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(text)
|
||||||
|
errorMessage = parsed.message || parsed.error || errorMessage
|
||||||
|
} catch {
|
||||||
|
// Если не JSON, используем текст как есть (но обрезаем до разумной длины)
|
||||||
|
if (text.length < 200) {
|
||||||
|
errorMessage = text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setToastMessage({ text: errorMessage, type: 'error' })
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error fetching metadata:', err)
|
console.error('Error fetching metadata:', err)
|
||||||
setToastMessage({ text: 'Ошибка при загрузке информации', type: 'error' })
|
const errorMessage = err.message || 'Ошибка при загрузке информации'
|
||||||
|
setToastMessage({ text: errorMessage, type: 'error' })
|
||||||
} finally {
|
} finally {
|
||||||
setFetchingMetadata(false)
|
setFetchingMetadata(false)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user