使用Go语言解析JSONP

我要如何解析JSONP?

How would I parse JSONP?
byu/SamosasAndCoffee ingolang


这篇文章讨论了如何将返回的数据从包含回调函数的JSONP格式转换成JSON,然后再转换成结构体的问题。

1) 我正在吃晚餐。
(Wǒ chī .)

func main() {
  jsonpStr := `
  callback({
    "hello": "world!!",
    "num": 123456
  });`

  var v interface{}
  err := json.Unmarshal(jsonpStr, &v)
  fmt.Println(err)
  // invalid character 'c' looking for beginning of value
  // JSONを期待しているのに先頭にcallbackという不要な文字列があるためUnmarshalがエラーを返します。
}

应对方法

以下是从reddit帖子的回答中选择的两个例子。

请提供一种titpetric先生的解决方式。

这是一种从头开始(到尾部,以及从尾部开始)用“trim”来处理的方法,YO!

    jsonpStr := `callback({
      "hello": "world!!",
      "num": 123456
    });`

    jsonStr := jsonpStr[strings.Index(jsonpStr, "(")+1 : strings.Index(jsonpStr, ")")]
    fmt.Println(jsonStr)
    // {
    //  "hello": "world!!",
    //  "num": 123456
    // }

    var v interface{}
    json.Unmarshal([]byte(jsonStr), &v)
    fmt.Printf("%+v", v)
    // map[hello:world!! num:123456]

jerf先生的应对方式

我們可以使用一種名為「YO!」的方法來作為io.Reader的包裝器。


type JSONPWrapper struct {
    Prefix     string
    Underlying io.Reader

    gotPrefix bool
}

func (jpw *JSONPWrapper) Read(b []byte) (int, error) {
    if jpw.gotPrefix {
        return jpw.Underlying.Read(b)
    }

    prefix := make([]byte, len(jpw.Prefix))
    n, err := io.ReadFull(jpw.Underlying, prefix)
    if err != nil {
        return n, err
    }

    if string(prefix) != jpw.Prefix {
        return n, fmt.Errorf("JSONP prefix mismatch: expected %q, got %q",
            jpw.Prefix, prefix)
    }

    // read until the (; in general, this should just be one read
    char := make([]byte, 1)
    for char[0] != '(' {
        n, err = jpw.Underlying.Read(char)
        if n == 0 || err != nil {
            return n, err
        }
    }

    // We've now consumed the JSONP prefix.
    jpw.gotPrefix = true
    return jpw.Underlying.Read(b)
}

func main() {
    jsonpStr := `callback({
      "hello": "world!!",
      "num": 123456
    });`
    prefix := "callback"
    jsonp := bytes.NewBuffer([]byte(jsonpStr))
    var decoded interface{}
    decoder := json.NewDecoder(&JSONPWrapper{Prefix: prefix, Underlying: jsonp})

    // This code depends on the fact the JSON parser stops when it
    // finishes a JSON object, so we don't have to handle the concluding
    // paren.
    decoder.Decode(&decoded)
    fmt.Println(decoded)
    // map[hello:world!! num:123456]
}

在调用 `json.NewDecoder` 时,将 `JSONPWrapper`(满足 `io.Reader` 接口的对象)作为参数传入,这将在调用 `decoder.Decode` 的时候执行 `JSONWrapper.Read()` 方法。
在 `JSONWrapper.Read()` 方法中,会将设置的前缀字符串与 JSONP 字符串的开头进行比较,并将其删除。

广告
将在 10 秒后关闭
bannerAds