jeessy2/ddns-go · error

读取 dnsla 响应失败: %w

Error message

读取 dnsla 响应失败: %w

What it means

After a successful HTTP exchange, request() reads the entire dnsla response body with io.ReadAll. If reading the body fails, it returns 读取 dnsla 响应失败 wrapping the cause. This indicates the connection dropped or was reset mid-response, or the response body stream errored.

Source

Thrown at dns/dnsla.go:236

	if err != nil {
		return nil, fmt.Errorf("创建 dnsla 请求失败: %w", err)
	}
	// 设置自定义 Headers
	byteBuff := []byte(dnsla.DNS.ID + ":" + dnsla.DNS.Secret)
	token := "Basic " + base64.StdEncoding.EncodeToString(byteBuff)
	req.Header.Set("Authorization", token)
	req.Header.Set("Content-Type", "application/json;charset=utf-8")
	// 4. 发送请求
	client := dnsla.httpClient
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("请求 dnsla 失败: %w", err)
	}
	defer resp.Body.Close()

	body, err = io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取 dnsla 响应失败: %w", err)
	}
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("dnsla 请求失败,状态码: %d, 响应: %s", resp.StatusCode, string(body))
	}
	return body, nil
}

// 获得域名记录列表
func (dnsla *Dnsla) getRecordList(domain *config.Domain, typ string) (result []byte, err error) {
	recordTypeInt := "1"
	if typ == "AAAA" {
		recordTypeInt = "28"
	}
	params := domain.GetCustomParams()
	params.Set("domain", domain.DomainName)
	params.Set("host", domain.GetSubDomain())
	params.Set("type", recordTypeInt)
	params.Set("pageIndex", "1")

View on GitHub (pinned to 5874c2e666)

Solutions

  1. Check the wrapped %w error for 'unexpected EOF'/'connection reset' vs timeout
  2. Retry the request — transient body read failures usually succeed on retry
  3. Increase httpClient.Timeout or use a context with a generous deadline for large responses
  4. Verify no intermediate proxy is truncating responses; test with curl to compare
  5. Use errors.Is/As on the wrapped cause to implement targeted retry logic

Example fix

// before
body, err = io.ReadAll(resp.Body)
if err != nil {
  return nil, fmt.Errorf("读取 dnsla 响应失败: %w", err)
}
// after
body, err = io.ReadAll(resp.Body)
if err != nil {
  if isRetryable(err) { // e.g. io.ErrUnexpectedEOF, ECONNRESET
    return dnsla.request(method, apiAddr, values) // simple retry
  }
  return nil, fmt.Errorf("读取 dnsla 响应失败: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

// nothing to check before the call; guard the read instead
lr := io.LimitReader(resp.Body, 1<<20) // cap size to avoid huge reads
body, err := io.ReadAll(lr)

Type guard

func isBodyReadErr(err error) bool {
  return errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, syscall.ECONNRESET)
}

Try / catch

body, err = io.ReadAll(resp.Body)
if err != nil {
  if isBodyReadErr(err) {
    return nil, retryable(fmt.Errorf("读取 dnsla 响应失败: %w", err))
  }
  return nil, fmt.Errorf("读取 dnsla 响应失败: %w", err)
}

Prevention

When it happens

Trigger: client.Do succeeded but io.ReadAll(resp.Body) fails: server closed the connection prematurely, network interruption during body transfer, timeout while reading a large body, or gzip/compression errors.

Common situations: Unstable network or mobile connection dropping mid-transfer; dnsla server-side errors truncating responses; proxy/CDN cutting long responses; very low client timeout interrupting body read.

Related errors


AI-assisted analysis of jeessy2/ddns-go@5874c2e666 (2026-09-03). Data as JSON: /api/errors/980d4149a787561a. Report an issue: GitHub.