Golang处理第三方API非标准JSON格式错误响应方案咨询
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_VALUEinstead 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

