flipped-aurora/gin-vue-admin · error

解析下载结果失败: %w

Error message

解析下载结果失败: %w

What it means

The marketplace's 200 response body could not be parsed as the expected JSON shape {"data":{"url":"..."}}. json.Unmarshal failed, meaning the response is not valid JSON or doesn't match the meta struct.

Source

Thrown at server/service/system/sys_skills.go:429

	}
	defer downloadResp.Body.Close()

	if downloadResp.StatusCode != http.StatusOK {
		return fmt.Errorf("下载技能失败, HTTP状态码: %d", downloadResp.StatusCode)
	}

	metaBody, err := io.ReadAll(downloadResp.Body)
	if err != nil {
		return fmt.Errorf("读取下载结果失败: %w", err)
	}

	var meta struct {
		Data struct {
			URL string `json:"url"`
		} `json:"data"`
	}
	if err = json.Unmarshal(metaBody, &meta); err != nil {
		return fmt.Errorf("解析下载结果失败: %w", err)
	}

	realDownloadURL := strings.TrimSpace(meta.Data.URL)
	if realDownloadURL == "" {
		return errors.New("下载结果缺少 url")
	}

	zipResp, err := http.Get(realDownloadURL)
	if err != nil {
		return fmt.Errorf("下载压缩包失败: %w", err)
	}
	defer zipResp.Body.Close()

	if zipResp.StatusCode != http.StatusOK {
		return fmt.Errorf("下载压缩包失败, HTTP状态码: %d", zipResp.StatusCode)
	}

	tmpFile, err := os.CreateTemp("", "gva-skill-*.zip")

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Dump/log the raw metaBody to see what was actually returned
  2. Verify the marketplace API response contract still nests the URL under data.url
  3. Check for proxy/WAF HTML responses and exclude them (Content-Type check before Unmarshal)
  4. Upgrade/redeploy if the server-side struct is stale relative to the marketplace API

Example fix

// add diagnostics before unmarshal
ct := downloadResp.Header.Get("Content-Type")
if !strings.Contains(ct, "application/json") {
    return fmt.Errorf("unexpected content-type %s: %s", ct, metaBody)
}
if err = json.Unmarshal(metaBody, &meta); err != nil { ... }
Defensive patterns

Strategy: type-guard

Validate before calling

resp, err := http.Post(downloadSkillURL, "application/json", body)
if err == nil && !strings.Contains(resp.Header.Get("Content-Type"), "application/json") {
    // response is not JSON (HTML error page/captcha) — abort early
}

Type guard

func isDownloadMeta(v interface{}) bool {
    m, ok := v.(map[string]interface{})
    if !ok { return false }
    d, ok := m["data"].(map[string]interface{})
    if !ok { return false }
    url, ok := d["url"].(string)
    return ok && url != ""
}

Try / catch

if err := DownloadOnlineSkill(ctx, req); err != nil && strings.Contains(err.Error(), "解析下载结果失败") {
    // marketplace contract changed or returned HTML; log body and check API version
}

Prevention

When it happens

Trigger: Calling DownloadOnlineSkill when the marketplace returns HTML (error page via proxy), an empty body, a different envelope (e.g. top-level url instead of data.url), or a captcha/WAF challenge page with 200 status.

Common situations: Marketplace API contract changed after an upgrade; transparent proxies returning HTML; hitting a wrong endpoint variant; CDN serving cached error pages.

Related errors


AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31). Data as JSON: /api/errors/8ca0dedd4f834540. Report an issue: GitHub.