From fc185c29ed96a3e4ff56ddd7b65439661ac3ba59 Mon Sep 17 00:00:00 2001 From: NewName Date: Tue, 20 May 2025 16:52:26 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=95=9C=E5=83=8F=E6=90=9C?= =?UTF-8?q?=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ghproxy/public/search.html | 41 +++++++++++++++------ ghproxy/search.go | 73 ++++++++++++++++++++++++++++++-------- 2 files changed, 89 insertions(+), 25 deletions(-) diff --git a/ghproxy/public/search.html b/ghproxy/public/search.html index 1a35dd7..e2de970 100644 --- a/ghproxy/public/search.html +++ b/ghproxy/public/search.html @@ -514,6 +514,7 @@ showLoading(); try { + console.log('执行搜索:', query); const response = await fetch(`/search?q=${encodeURIComponent(query)}`); const data = await response.json(); @@ -521,10 +522,11 @@ throw new Error(data.error || '搜索请求失败'); } + console.log('搜索响应:', data); displayResults(data.results); } catch (error) { - showToast('搜索失败,请稍后重试'); console.error('搜索错误:', error); + showToast(error.message || '搜索失败,请稍后重试'); } finally { hideLoading(); } @@ -565,10 +567,13 @@ return; } + console.log('显示搜索结果:', results); + results.forEach(result => { const card = document.createElement('div'); card.className = 'result-card'; + // 确保所有字段都有值 const name = result.name || ''; const namespace = result.namespace || ''; const description = result.description || '暂无描述'; @@ -580,6 +585,14 @@ const orgBadge = result.organization ? `By ${result.organization}` : ''; const automatedBadge = result.is_automated ? '自动构建' : ''; + console.log('处理仓库:', { + name, + namespace, + repoName, + isOfficial: result.is_official, + organization: result.organization + }); + card.innerHTML = `
${repoName} @@ -598,8 +611,9 @@ `; card.addEventListener('click', () => { + console.log('点击仓库:', name, namespace); currentRepo = result; - loadTags(result.namespace || 'library', result.name); + loadTags(namespace || 'library', name); }); resultsContainer.appendChild(card); @@ -609,18 +623,25 @@ async function loadTags(namespace, name) { showLoading(); try { - const response = await fetch(`/tags/${namespace}/${name}`); - const tags = await response.json(); - - if (!response.ok) { - throw new Error(tags.error || '获取标签信息失败'); + console.log('加载标签:', namespace, name); + if (!name) { + showToast('镜像名称不能为空'); + return; } - displayTags(tags); + const response = await fetch(`/tags/${namespace}/${name}`); + const data = await response.json(); + + if (!response.ok) { + throw new Error(data.error || '获取标签信息失败'); + } + + console.log('标签数据:', data); + displayTags(data); showTagList(); } catch (error) { - showToast('获取标签信息失败,请稍后重试'); - console.error('获取标签错误:', error); + console.error('加载标签错误:', error); + showToast(error.message || '获取标签信息失败,请稍后重试'); } finally { hideLoading(); } diff --git a/ghproxy/search.go b/ghproxy/search.go index 59b9216..3daca11 100644 --- a/ghproxy/search.go +++ b/ghproxy/search.go @@ -104,13 +104,16 @@ func searchDockerHub(ctx context.Context, query string, page, pageSize int) (*Se } // 构建Docker Hub API请求 - baseURL := "https://hub.docker.com/v2/search/repositories/" + baseURL := "https://registry.hub.docker.com/v2/search/repositories/" params := url.Values{} params.Set("query", query) params.Set("page", fmt.Sprintf("%d", page)) params.Set("page_size", fmt.Sprintf("%d", pageSize)) - req, err := http.NewRequestWithContext(ctx, "GET", baseURL+"?"+params.Encode(), nil) + fullURL := baseURL + "?" + params.Encode() + fmt.Printf("搜索URL: %s\n", fullURL) + + req, err := http.NewRequestWithContext(ctx, "GET", fullURL, nil) if err != nil { return nil, fmt.Errorf("创建请求失败: %v", err) } @@ -127,19 +130,33 @@ func searchDockerHub(ctx context.Context, query string, page, pageSize int) (*Se } defer resp.Body.Close() + // 读取响应体 + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("读取响应失败: %v", err) + } + // 检查响应状态码 if resp.StatusCode != http.StatusOK { - body, _ := io.ReadAll(resp.Body) return nil, fmt.Errorf("请求失败: 状态码=%d, 响应=%s", resp.StatusCode, string(body)) } + // 打印响应内容以便调试 + fmt.Printf("搜索响应: %s\n", string(body)) + // 解析响应 var result SearchResult - if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + if err := json.Unmarshal(body, &result); err != nil { return nil, fmt.Errorf("解析响应失败: %v", err) } - // 缓存结果 + // 打印解析后的结果 + fmt.Printf("搜索结果: 总数=%d, 结果数=%d\n", result.Count, len(result.Results)) + for i, repo := range result.Results { + fmt.Printf("仓库[%d]: 名称=%s, 命名空间=%s, 描述=%s, 是否官方=%v\n", + i, repo.Name, repo.Namespace, repo.Description, repo.IsOfficial) + } + setCacheResult(cacheKey, &result) return &result, nil } @@ -154,16 +171,19 @@ func getRepositoryTags(ctx context.Context, namespace, name string) ([]TagInfo, // 构建API URL var baseURL string if namespace == "library" { - baseURL = fmt.Sprintf("https://hub.docker.com/v2/repositories/library/%s/tags", name) + baseURL = fmt.Sprintf("https://registry.hub.docker.com/v2/repositories/library/%s/tags", name) } else { - baseURL = fmt.Sprintf("https://hub.docker.com/v2/repositories/%s/%s/tags", namespace, name) + baseURL = fmt.Sprintf("https://registry.hub.docker.com/v2/repositories/%s/%s/tags", namespace, name) } params := url.Values{} params.Set("page_size", "100") params.Set("ordering", "last_updated") - req, err := http.NewRequestWithContext(ctx, "GET", baseURL+"?"+params.Encode(), nil) + fullURL := baseURL + "?" + params.Encode() + fmt.Printf("获取标签URL: %s\n", fullURL) + + req, err := http.NewRequestWithContext(ctx, "GET", fullURL, nil) if err != nil { return nil, fmt.Errorf("创建请求失败: %v", err) } @@ -180,12 +200,20 @@ func getRepositoryTags(ctx context.Context, namespace, name string) ([]TagInfo, } defer resp.Body.Close() + // 读取响应体 + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("读取响应失败: %v", err) + } + // 检查响应状态码 if resp.StatusCode != http.StatusOK { - body, _ := io.ReadAll(resp.Body) return nil, fmt.Errorf("请求失败: 状态码=%d, 响应=%s", resp.StatusCode, string(body)) } + // 打印响应内容以便调试 + fmt.Printf("标签响应: %s\n", string(body)) + // 解析响应 var result struct { Count int `json:"count"` @@ -193,11 +221,17 @@ func getRepositoryTags(ctx context.Context, namespace, name string) ([]TagInfo, Previous string `json:"previous"` Results []TagInfo `json:"results"` } - if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + if err := json.Unmarshal(body, &result); err != nil { return nil, fmt.Errorf("解析响应失败: %v", err) } - // 缓存结果 + // 打印解析后的结果 + fmt.Printf("标签结果: 总数=%d, 结果数=%d\n", result.Count, len(result.Results)) + for i, tag := range result.Results { + fmt.Printf("标签[%d]: 名称=%s, 大小=%d, 更新时间=%v\n", + i, tag.Name, tag.FullSize, tag.LastUpdated) + } + setCacheResult(cacheKey, result.Results) return result.Results, nil } @@ -222,14 +256,15 @@ func RegisterSearchRoute(r *gin.Engine) { } // 如果是搜索官方镜像 - if strings.HasPrefix(query, "library/") || !strings.Contains(query, "/") { - if !strings.HasPrefix(query, "library/") { - query = "library/" + query - } + if !strings.Contains(query, "/") { + query = "library/" + query } + fmt.Printf("搜索请求: query=%s, page=%d, pageSize=%d\n", query, page, pageSize) + result, err := searchDockerHub(c.Request.Context(), query, page, pageSize) if err != nil { + fmt.Printf("搜索失败: %v\n", err) c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } @@ -242,8 +277,16 @@ func RegisterSearchRoute(r *gin.Engine) { namespace := c.Param("namespace") name := c.Param("name") + fmt.Printf("获取标签请求: namespace=%s, name=%s\n", namespace, name) + + if namespace == "" || name == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "命名空间和名称不能为空"}) + return + } + tags, err := getRepositoryTags(c.Request.Context(), namespace, name) if err != nil { + fmt.Printf("获取标签失败: %v\n", err) c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return }