V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
whoami9894
V2EX  ›  Go 编程语言

使用 Golang 的 json 解析库遇到的一点问题

  •  
  •   whoami9894 · 2019-05-30 17:37:15 +08:00 · 9534 次点击
    这是一个创建于 2006 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一个请求 ISBN 查询 API 的服务,查询信息的字段是:

    type info struct {
    	ISBN       string `json:"isbn"`
    	Title      string `json:"title"`
    	Subtitle   string `json:"subtitle"`
    	Pic        string `json:"pic"`
    	Author     string `json:"author"`
    	Summary    string `json:"summary"`
    	Publisher  string `json:"publisher"`
    	Pubplace   string `json:"pubplace"`
    	Page       int    `json:"page"`
    	Price      string `json:"price"`
    	Binding    string `json:"binding"`
    	Keyword    string `json:"keyword"`
    	Edition    string `json:"edition"`
    	Impression string `json:"impression"`
    	Language   string `json:"language"`
    	Format     string `json:"format"`
    	Class      string `json:"class"`
    }
    

    这里的 page 最初我写了 string 类型,然后解析报错了json: cannot unmarshal number into Go value of type string

    然后我改为了 int 类型,然后依然会时不时报错json: cannot unmarshal string into Go struct field info.page of type int???昨天报错了几次,之后却一直正常想复现都不行,今天又报错了。查验了那个 ISBN API 应该没有问题,给的 page 就是 integer

    但是这里报错后却插入数据库了,逻辑是这样的:

    func get(isbn string) (*info, error) {
    	url := baseURL + isbn
    	resp, err := nic.Get(url, nil)
    	if err != nil {
    		return nil, err
    	}
    
    	t := &tmp{0, "", &info{}}
    	err = resp.JSON(t)   //***************************************** error here
    	if err != nil {
    		return nil, err
    	}
    	if t.Status != 0 {
    		return nil, errors.New(t.Msg)
    	}
    
    	return t.Result, nil
    }
    
    func query(c *mgo.Collection, isbn string) (*info, error) {
    	data := &info{}
    	c.Find(bson.M{"isbn": isbn}).One(data)
    
    	if data.ISBN == "" {
    		var err error
    		data, err = get(isbn)
    		if err != nil {
    			return nil, err
    		}
    		err = c.Insert(data)
    		if err != nil {
    			return nil, err
    		}
    	}
    	return data, nil
    }
    

    而且第一次报错后插入数据库的数据却是正确的,page 就是正确的 integer:

     {'isbn': '9787212053937', 'page': 236, 'price': '21.50', 'binding': '', 'keyword': '', 'edition': '', 'impression': '', 'language': '', 'format': '', 'class': ''}
    

    orz

    16 条回复    2019-06-03 09:10:26 +08:00
    whoami9894
        1
    whoami9894  
    OP
       2019-05-30 17:42:13 +08:00 via Android
    我知道了,貌似是 mgo 报的错
    wangsongyan
        2
    wangsongyan  
       2019-05-30 18:44:08 +08:00 via iPhone
    如果是因为字段类型不一致,可以试试 json.Number
    petelin
        3
    petelin  
       2019-05-30 18:56:20 +08:00 via iPhone
    估计有 number 有 string
    whoami9894
        4
    whoami9894  
    OP
       2019-05-30 19:13:00 +08:00
    @wangsongyan
    @petelin

    感谢回复,我又测试了一下,果然这个 zz 的 API 第一次请求返回 int 之后都返回 string,服了......

    ```
    2019/05/30 19:08:29 int
    2019/05/30 19:08:29 {"status":0,"msg":"ok","result":{"title":"课本全解( 5 年级上)","
    author":null,"subtitle":null,"pubdate":" 2012-7","page":" 236","price":" 21.50 元","s ummary":"","pic":"http:\/\/api.jisuapi.com\/isbn\/\/upload\/3663\/3662449.","isbn":"9787212053928","isbn10":"7212053929","sellerlist":[{"seller":"douban","price":"21.50"}]}}
    2019/05/30 19:08:29 89
    2019/05/30 19:08:29 json: cannot unmarshal string into Go struct field info.page of type int

    [GIN] 2019/05/30 - 19:08:29 | 200 | 1.5377224s | 127.0.0.1 | POST /api/v1/isbn-query
    2019/05/30 19:10:06 int
    2019/05/30 19:10:06 {"status":0,"msg":"ok","result":{"title":"课本全解( 5 年级上)","
    subtitle":null,"pic":"http:\/\/api.jisuapi.com\/isbn\/upload\/3663\/3662449.","author":null,"summary":null,"publisher":null,"pubplace":null,"pubdate":" 2012-7","page":236,"price":"21.50","binding":null,"isbn":"9787212053928","isbn10":"7212053929","keyword":null,"edition":null,"impression":null,"language":null,"format":null,"class":null,"sellerlist":[{"seller":"douban","price":"21.50"}]}}
    [GIN] 2019/05/30 - 19:10:06 | 200 | 176.5282ms | 127.0.0.1 | POST /api/v1/isbn-query
    [GIN] 2019/05/30 - 19:10:16 | 200 | 0s | 127.0.0.1 | POST /api/v1/isbn-query
    ```
    Trim21
        5
    Trim21  
       2019-05-30 19:30:25 +08:00 via Android
    初学 golang,正好看到这个问题,请教下,这样类型不确定的 json 要怎么解析?
    whoami9894
        6
    whoami9894  
    OP
       2019-05-30 19:45:39 +08:00
    @wangsongyan
    @petelin
    json.Number 有点问题,page 字段可能返回空`"page": null,`,用 json.Number 就报错了`failed to convert json.Number to a number:`,改成了 interface{}暂时测试没什么问题
    whoami9894
        7
    whoami9894  
    OP
       2019-05-30 19:47:06 +08:00
    @Trim21
    我这里把 page 定义成空接口类型了,假如之后需要这个确定类型的话再做类型断言就行
    Reficul
        8
    Reficul  
       2019-05-30 20:23:28 +08:00   ❤️ 8
    对于要兼容这种奇葩的字段,可以这样:

    type Number int64

    然后给这个 Number 实现 json.Unmarshaler 接口来自定义解析逻辑。
    whoami9894
        9
    whoami9894  
    OP
       2019-05-30 20:45:57 +08:00 via Android
    @Reficul 感谢回复,学到了
    donething
        10
    donething  
       2019-05-30 22:24:32 +08:00
    @Reficul 感谢,这个方法好。
    Allianzcortex
        11
    Allianzcortex  
       2019-05-30 22:42:35 +08:00 via iPhone
    @Reficul 厉害
    JimmyTinsley
        12
    JimmyTinsley  
       2019-05-31 08:59:16 +08:00
    我倒是挺好奇这个 api 是怎么实现一会儿返回 int 一会儿返回 string 的...
    wweir
        13
    wweir  
       2019-05-31 10:37:44 +08:00
    @liujie333333 动态类型语言比较容易出现这样的情况,当然,还是看使用者的水平
    janxin
        14
    janxin  
       2019-05-31 11:21:53 +08:00
    @Trim21 最理想是 interface{},什么都能收,然后根据具体类型做处理
    whoami9894
        15
    whoami9894  
    OP
       2019-05-31 11:55:10 +08:00
    @liujie333333
    最逗的是这个 API 文档告诉我类型是 string,然后第一次请求返回 string 之后请求全是 int,可能跟服务端某些缓存机制有关
    lxz6597863
        16
    lxz6597863  
       2019-06-03 09:10:26 +08:00
    https://github.com/json-iterator/go 这个包有个 Any 类型,可以试下
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5781 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 03:00 · PVG 11:00 · LAX 19:00 · JFK 22:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.