You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang处理第三方API非标准JSON格式错误响应方案咨询

How to Parse Malformed "JSON-like" API Response in Golang

I get it, dealing with APIs that return non-standard, pseudo-JSON responses is super frustrating—especially when you're trying to use Go's strict encoding/json package. Let's break down how to fix the messy response you got and parse it properly.

The Problem Recap

Your API response looks like JSON but has several invalid quirks:

  • Keys aren't wrapped in double quotes (e.g., reason=CONDITIONAL_INVALID_VALUE instead of "reason":"CONDITIONAL_INVALID_VALUE")
  • Uses = instead of : for key-value pairs
  • Nested structures have unquoted keys/values too

Solution: Preprocess the Raw Response First

We'll clean up the malformed string to turn it into valid JSON, then parse it with Go's standard JSON tools. Here's a step-by-step implementation:

1. Define Structs for Parsing

First, create structs that match the cleaned-up JSON structure. This makes it easy to work with the data after parsing:

package main

import (
    "encoding/json"
    "fmt"
    "regexp"
)

// APIError represents the top-level error response
type APIError struct {
    Message string `json:"message"`
    Status  int    `json:"status"`
}

// ValidationError represents each individual validation failure in the message
type ValidationError struct {
    Reason     string            `json:"reason"`
    Field      string            `json:"field"`
    BatchIndex int               `json:"batchIndex"`
    Type       string            `json:"type"`
    Message    string            `json:"message"`
    Parameters map[string]string `json:"parameters"`
}

2. Preprocess the Raw String

Write a helper function to fix the invalid syntax. We'll use regex to:

  • Wrap keys in quotes and replace = with :
  • Wrap string values in quotes (leave numbers as-is)
  • Fix any edge cases like empty key values
func preprocessMalformedResponse(raw string) string {
    // Step 1: Convert keys like `reason=` to `"reason":`
    reKeys := regexp.MustCompile(`(\w+)=`)
    processed := reKeys.ReplaceAllString(raw, `"$1":`)

    // Step 2: Wrap non-numeric, non-struct values in quotes
    // Matches values that aren't digits, {, }, or commas
    reValues := regexp.MustCompile(`:\s*([^\d{},\s]+)`)
    processed = reValues.ReplaceAllString(processed, `:"$1"`)

    // Step 3: Handle empty values (e.g., `key=}}` becomes `"key":""}}`)
    reEmpty := regexp.MustCompile(`:"\s*}`)
    processed = reEmpty.ReplaceAllString(processed, `:""}`)

    return processed
}

3. Parse the Cleaned JSON

Now you can take the preprocessed string and parse it into your structs. Note that the message field has a prefix we need to trim before parsing the array of validation errors:

func main() {
    // Your raw malformed response
    rawResponse := `{ "message": "Validation failed because [{reason=CONDITIONAL_INVALID_VALUE, field=/targetingCriteria, batchIndex=0, type=INVALID_VALUE, message=/locale cannot be set to en if urn:li:adTargetingFacet:interfaceLocales is set to urn:li:locale:it_IT, parameters={field1=/locale, value2=urn:li:locale:it_IT, value1=en, field2=urn:li:adTargetingFacet:interfaceLocales, key=}}, {reason=FIELD_VALUE_TOO_LOW, field=dailyBudget, batchIndex=0, type=INVALID_VALUE, message=/dailyBudget/amount value 1 cannot be lower than 10.00, parameters={min=10.00, field=/dailyBudget/amount, costType=CPM, type=SPONSORED_UPDATES, value=1, key=}}]", "status": 400 }`

    // Clean up the response
    cleaned := preprocessMalformedResponse(rawResponse)

    // Parse top-level API error
    var apiErr APIError
    if err := json.Unmarshal([]byte(cleaned), &apiErr); err != nil {
        fmt.Printf("Failed to parse top-level error: %v\n", err)
        return
    }

    // Trim the prefix from the message to get the raw error array
    trimmedMessage := apiErr.Message[len("Validation failed because "):]
    
    // Parse the validation errors
    var validationErrs []ValidationError
    if err := json.Unmarshal([]byte(trimmedMessage), &validationErrs); err != nil {
        fmt.Printf("Failed to parse validation errors: %v\n", err)
        return
    }

    // Now you can work with the parsed data!
    fmt.Printf("Status Code: %d\n", apiErr.Status)
    for i, err := range validationErrs {
        fmt.Printf("\nValidation Error #%d:\n", i+1)
        fmt.Printf("  Reason: %s\n", err.Reason)
        fmt.Printf("  Field: %s\n", err.Field)
        fmt.Printf("  Message: %s\n", err.Message)
        fmt.Printf("  Parameters: %v\n", err.Parameters)
    }
}

Key Notes

  • The regex approach works for this specific response format, but keep an eye on the API—if they change their error format, you might need to tweak the regex.
  • This method avoids heavy external dependencies and leverages Go's standard library tools.

内容的提问来源于stack exchange,提问作者Matteo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:39:07