fish2018/pansou · error

解析响应失败

Error message

解析响应失败: %w

What it means

After a successful request, fetchPage unmarshals the response body into BixinResponse with json.Unmarshal; this error wraps any parse failure. It means the body is not valid JSON or its shape does not match BixinResponse (e.g. an HTML error page or a different field type). Unlike transport errors, no retry is attempted here.

Solutions

  1. Log a snippet of responseBody to see whether it's HTML, empty, or JSON with a different schema.
  2. Add a content-type check (must be application/json) before unmarshalling.
  3. Update the BixinResponse struct tags to match the current API schema.
  4. Use json.Unmarshal with a generic map first to inspect the actual shape when debugging.

Example fix

// before
var apiResp BixinResponse
if err := json.Unmarshal(responseBody, &apiResp); err != nil {
    return nil, false, fmt.Errorf("解析响应失败: %w", err)
}
// after
if !json.Valid(responseBody) {
    return nil, false, fmt.Errorf("响应不是有效JSON: %q", responseBody[:min(len(responseBody),200)])
}
var apiResp BixinResponse
if err := json.Unmarshal(responseBody, &apiResp); err != nil {
    return nil, false, fmt.Errorf("解析响应失败: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

body, _ := io.ReadAll(resp.Body)
if !json.Valid(body) {
    return fmt.Errorf("响应不是有效JSON")
}
if ct := resp.Header.Get("Content-Type"); !strings.Contains(ct, "application/json") {
    return fmt.Errorf("意外的Content-Type: %s", ct)
}

Type guard

func isValidBixinJSON(body []byte) bool {
    var probe struct {
        Data []json.RawMessage `json:"data"`
    }
    return json.Unmarshal(body, &probe) == nil
}

Try / catch

results, err := plugin.Search(ctx, keyword)
if err != nil {
    var parseErr *json.SyntaxError
    if errors.As(err, &parseErr) {
        log.Printf("bixin返回了非JSON内容(偏移%d): %v", parseErr.Offset, parseErr)
    }
}

Prevention

When it happens

Trigger: json.Unmarshal(responseBody, &apiResp) fails in fetchPage — response body is HTML (anti-bot page), empty, truncated, or JSON fields have types that don't match BixinResponse's struct tags.

Common situations: Site returns an HTML login/challenge page instead of JSON, API version changed its response schema, or a non-JSON error body slipped through because only status code was checked.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/53f3c62c437f8f1b. Report an issue: GitHub.

Appendix: source

Thrown at plugin/bixin/bixin.go:241

		}
		
		// 状态码检查
		if resp.StatusCode != http.StatusOK {
			if i == p.retries {
				return nil, false, fmt.Errorf("API返回非200状态码: %d", resp.StatusCode)
			}
			time.Sleep(500 * time.Millisecond)
			continue
		}
		
		// 请求成功,跳出重试循环
		break
	}
	
	// 解析响应
	var apiResp BixinResponse
	if err := json.Unmarshal(responseBody, &apiResp); err != nil {
		return nil, false, fmt.Errorf("解析响应失败: %w", err)
	}
	
	// 处理结果
	results := make([]model.SearchResult, 0, len(apiResp.Data))
	postMap := make(map[string]BixinPost)
	
	// 创建帖子ID到帖子内容的映射
	for _, post := range apiResp.Included {
		postMap[post.ID] = post
	}
	
	// 遍历搜索结果
	for _, discussion := range apiResp.Data {
		// 获取相关帖子
		postID := discussion.Relationships.MostRelevantPost.Data.ID
		post, ok := postMap[postID]
		if !ok {
			continue

View on GitHub (pinned to beaa561337)