V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
DreamSpace
V2EX  ›  Java

关于 GET 请求中的数组格式

  •  
  •   DreamSpace · 2019-08-29 11:13:15 +08:00 · 14387 次点击
    这是一个创建于 1918 天前的主题,其中的信息可能已经有所发展或是发生改变。

    今天上班摸鱼摸得正起劲,前端同事发来一条消息说调我接口时报错:

    接口:

        @GetMapping(value = "/getList")
        public ResponseMessage getList(IpcDeviceQuery query);
    

    参数:

    	/getList?groupIdList[]=2&groupIdList[]=3
    

    报错:

    	Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
    

    粗略看了一下,是 GET 请求中数组格式的问题,前端同事使用的格式并不能被 Springboot 的后端接收到。

    网上查了查资料,发现 GET 请求传输数组参数的方式百花齐放,各种格式都有,归纳了一下,大概以下三种格式:

    • 格式 1:?groupIdList=2&groupIdList=3
    • 格式 2:?groupIdList[]=2&groupIdList[]=3
    • 格式 3:?groupIdList[0]=2&groupIdList[1]=3

    哪一种格式是真正符合规范的? Spring 需要定制什么才能解析格式 2 和格式 3 的参数呢?

    39 条回复    2019-08-30 12:54:44 +08:00
    mikoshu
        1
    mikoshu  
       2019-08-29 11:19:19 +08:00
    get 请求传啥数组 让他直接把字符串用逗号隔开给你呗
    chendy
        2
    chendy  
       2019-08-29 11:20:09 +08:00
    url 参数本身就是多值的,只不过一般用不到:n=1,2,3,4 或者 n=1&n=2&n=3&n=4
    一旦要用到复杂对象结构和数组,就直接用 POST 吧,省心省事
    chendy
        3
    chendy  
       2019-08-29 11:20:55 +08:00
    忘了说 n=1,2,3,4 或者 n=1&n=2&n=3&n=4 至少 SpringMVC 可以直接用数组和集合接
    baronOvO
        4
    baronOvO  
       2019-08-29 11:20:58 +08:00
    我觉得 1 楼说的对
    Humorce
        5
    Humorce  
       2019-08-29 11:21:09 +08:00
    路由都不规范为什么参数格式要规范呢?
    me876
        6
    me876  
       2019-08-29 11:29:26 +08:00   ❤️ 5
    让前端用 qs 库转换下后端能接收的格式就行,这个坑我之前也踩过。

    ```
    qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })
    // 'a[0]=b&a[1]=c'
    qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })
    // 'a[]=b&a[]=c'
    qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })
    // 'a=b&a=c'
    qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'comma' })
    // 'a=b,c'
    ```
    index90
        7
    index90  
       2019-08-29 11:31:14 +08:00
    记得是推荐格式 1
    whitev2
        8
    whitev2  
       2019-08-29 11:31:20 +08:00
    get 请求也是可以有请求体的,放请求体里

    @chendy #2
    ipwx
        9
    ipwx  
       2019-08-29 11:33:14 +08:00 via Android   ❤️ 1
    批量的接口为啥不用 post
    DreamSpace
        10
    DreamSpace  
    OP
       2019-08-29 11:44:18 +08:00
    @chendy 感谢,测试了下的以逗号分隔的确可以比较方便的接受

    @ipwx 因为是查询数据的接口,具有幂等性的,所以使用的是 GET
    ipwx
        11
    ipwx  
       2019-08-29 11:50:52 +08:00 via Android
    @DreamSpace 我个人觉得幂等性这种概念在这个例子上不重要。首先,批量接口组合数太多,基本没有 http 层缓存的价值。其次,get 参数无法应对大量 ID 的请求,还是得上 post。那些说 get 加上 body 的做法,我觉得那比违反所谓的幂等性更糟糕。综上,我觉得该用 post
    wysnylc
        12
    wysnylc  
       2019-08-29 11:57:59 +08:00
    1 是正确的 2,3 是什么鬼
    现在一般都转成 json &n=[1,2,3]这种形式传输
    PerpetualHeng
        13
    PerpetualHeng  
       2019-08-29 12:11:51 +08:00
    我先说第一点,从来没有 url 传参上会带上"[]"这种符号,即使是数据也是第一种方式。
    第二传数组一般都是搞成 json 传,后端转一下。
    涉及到这种传数组的请求,数据大小可以无限制,还是用 post 吧。
    Vegetable
        14
    Vegetable  
       2019-08-29 12:15:39 +08:00
    DavidNineRoc
        15
    DavidNineRoc  
       2019-08-29 12:28:19 +08:00
    多年的经验
    1 肯定是不行的,参数后面的会覆盖前面的值
    2,3 都行,因为不写索引,会类似 js 的数组,索引会自增。
    *****
    说 2,3 不行的,表单字段数组类型的没用过?
    代码已复制,请直接使用
    <!DOCTYPE HTML>
    <html lang="en-US">
    <head>
    <meta charset="UTF-8">
    <title></title>
    </head>
    <body>
    <form action="">
    <input type="text" name="tags[]" />
    <input type="text" name="tags[]" />
    <input type="text" name="tags[]" />
    <input type="text" name="tags[]" />
    <button type="submit">提交</button>
    </form>
    </body>
    </html>
    DavidNineRoc
        16
    DavidNineRoc  
       2019-08-29 12:29:34 +08:00
    之所以不行的原因,多半是因为你前端对象没有 urlencode 吧
    TabGre
        17
    TabGre  
       2019-08-29 12:34:09 +08:00 via iPhone
    6 楼说的有道理,前端可以自己拼接成你可以解析的形式,手动或者 qs 库
    Sparetire
        18
    Sparetire  
       2019-08-29 12:41:00 +08:00 via Android
    都可以,事实上就 HTTP 而言并没有限制你用哪种,甚至也不需要是 key=value 这样的格式,也都是合法的,这些格式都是框架的约定而已
    所以后端能处理哪种就传哪种就行了
    LokiSharp
        19
    LokiSharp  
       2019-08-29 13:11:37 +08:00
    get 也可以带 body 的啊
    whitev2
        20
    whitev2  
       2019-08-29 13:34:16 +08:00
    @Vegetable #14 A payload within a GET request message has no defined semantics;
    sending a payload body on a GET request might cause some existing
    implementations to reject the request.没有说不行,只是服务端可能不拿来用而已
    Vegetable
        21
    Vegetable  
       2019-08-29 14:53:41 +08:00   ❤️ 1
    @DavidNineRoc 1 是可以的,不会覆盖,世界上不是只有你一个明白人。
    MonoLogueChi
        22
    MonoLogueChi  
       2019-08-29 15:05:57 +08:00 via Android
    我以前也写过数组,感觉 1 用的比较多,在网上也看过别人用 2 和 3 这种,我自己也用过 1 这种格式。另外路由写好了怎么搞都可以,比如 a.com/api/query/300,301,302,303,使用后面这种格式的时候,fetch 请求特别的方便。

    springboot 没用过,我也不知道怎么搞才能支持后面的,感觉这种东西应该尽量让前端去修改请求,而不是后端修改接口
    sujin190
        23
    sujin190  
       2019-08-29 15:36:11 +08:00
    @whitev2 #20 但是浏览器包括大部分的库实现都会忽略 GET 请求中发送的 body,所以,协议说可以并没有什么用,还是得看现实啊
    azh7138m
        24
    azh7138m  
       2019-08-29 15:46:35 +08:00   ❤️ 2
    @DavidNineRoc
    1 必然受到支持
    https://tools.ietf.org/html/rfc6570#section-3.2.8

    我推荐 2,解析不了就是后端太蔡了(
    willxiang
        25
    willxiang  
       2019-08-29 16:20:24 +08:00
    直接 24L 连接里选“?list=red,green,blue ”这种不是一目了然了吗,后端拿到直接逗号分割
    SoloCompany
        26
    SoloCompany  
       2019-08-29 16:29:42 +08:00
    以 jquery 为例子

    假设请求为: {a:{one:1, two:2, three:3}, b:[1,2,3]}
    需要 uri encode

    那么
    传统风格编码为: a=[object+Object]&b=1&b=2&b=3
    即 格式 1
    因为传统风格并不支持 object 嵌套, a 会被 to string 然后丢失信息

    后来改进的风格编码为
    a[one]=1&a[two]=2&a[three]=3&b[]=1&b[]=2&b[]=3
    即 格式 2

    格式 3 我暂时没见过哪个框架会使用
    momocraft
        27
    momocraft  
       2019-08-29 16:37:07 +08:00
    复杂参数没有规范
    我记得 rfc 连 uri query 的严格定义都无
    x66
        28
    x66  
       2019-08-29 17:09:21 +08:00
    URL 都不标准,为何这么在意参数,用 POST 大法好
    xiangyuecn
        29
    xiangyuecn  
       2019-08-29 17:26:33 +08:00
    各位大佬,请教一下,Map<String,String> 接口有没有实现了多值的字典类呀? C# 有 NameValueCollection,java 不知道是哪个类,注意:是<String,String> 不是<String, List<String>>哦


    因为至今没有学会如何生成一个正常的 Android WebView 响应 WebResourceResponse,因为它的一个参数 Map<String, String> responseHeaders 我不知道用什么类的实例去填 😂😂😂😂

    典型的根请求参数一样,这是一个多值的问题,比如 Set-Cookie 响应头就见得多的是很多个

    https://developer.android.google.cn/reference/android/webkit/WebResourceResponse.html#WebResourceResponse(java.lang.String,%20java.lang.String,%20int,%20java.lang.String,%20java.util.Map%3Cjava.lang.String,%20java.lang.String%3E,%20java.io.InputStream)
    chocotan
        30
    chocotan  
       2019-08-29 17:35:47 +08:00
    错误提示里规范都出来了,很显然是没有 urlencode
    quericy
        31
    quericy  
       2019-08-29 18:09:48 +08:00   ❤️ 3
    不建议用格式 1,不同语言和容器对同名参数的默认处理方式可能会不一样。
    如果无法确保服务端配置合理的话,可能会有 HTTP 参数污染(HPP)攻击的风险
    Alexhohom
        32
    Alexhohom  
       2019-08-29 18:43:16 +08:00 via Android
    @Vegetable 不会覆盖,那用什么方法取值呢?需要自写解析函数吗?
    w516322644
        33
    w516322644  
       2019-08-29 18:45:04 +08:00
    我记得 1 被覆盖过啊。
    后来就是 2 那种
    w516322644
        34
    w516322644  
       2019-08-29 18:47:58 +08:00
    @willxiang 这种唯一问题,就是怕字符串有,
    dany813
        35
    dany813  
       2019-08-29 19:56:49 +08:00
    用 qs 库吧
    lululau
        36
    lululau  
       2019-08-29 20:00:35 +08:00 via iPhone
    第一种是 servlet 支持的,springmvc 三种都可以
    no1xsyzy
        37
    no1xsyzy  
       2019-08-30 10:06:35 +08:00
    这么烦直接 jsonrpc 好不好啊
    zjyl1994
        38
    zjyl1994  
       2019-08-30 11:33:12 +08:00
    我们一般用的都是逗号分隔的字符串
    luozic
        39
    luozic  
       2019-08-30 12:54:44 +08:00
    为啥不 urlencode,服务端获取的请求到底长啥样?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5368 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 05:48 · PVG 13:48 · LAX 21:48 · JFK 00:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.