如果浏览器发送的 HTTP Request 中使用了 Keep-alive,服务器如何得知这个 Request 已经读取完成? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
httpbin - 协议调试工具
httpstatuses - 协议状态码查询
httpie - cURL-like tool for humans
Fiddler
KyL
V2EX    HTTP

如果浏览器发送的 HTTP Request 中使用了 Keep-alive,服务器如何得知这个 Request 已经读取完成?

  •  
  •   KyL 2016-02-06 18:18:49 +08:00 5024 次点击
    这是一个创建于 3536 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一般当浏览器发送完 Request 之后就会半关闭 socket ,这会使得服务器中read()返回 0 ,服务器就知道 Request 已经读完了,然后根据 Request 可以生成 Response ,然后发回浏览器去(貌似是这样的吧?)

    如果 Request 中有 Keep-alive 的话,浏览器就不会关闭 socket ,那么服务器中的read()将会阻塞(阻塞状态)或者返回负值(非阻塞状态)。在这种情况下,服务器如果得知 Request 已经发送完了呢?是 Request 里面有长度信息吗?

    本人对于 HTTP 理解不是很透彻,望大神答疑解惑。

    19 条回复    2016-02-18 13:46:23 +08:00
    vietor
        1
    vietor  
       2016-02-06 18:39:47 +08:00 via Android
    分析已接收内容,头和 content-length
    jasontse
        2
    jasontse  
       2016-02-06 18:48:13 +08:00 via iPad
    Header 传送完毕时会有两个 \n
    rcmerci
        3
    rcmerci  
       2016-02-06 18:56:04 +08:00
    不是应该 浏览器发完 request 后等着 response ,等到了就把 socket 关了。
    要是发完 request 就关 socket 还怎么读 response 呀。
    另外, request 结尾有 2 个\n
    jybox
        4
    jybox  
       2016-02-06 18:58:11 +08:00
    一种情况是一楼说的 Content-Length, 还有一种是 Transfer-Encoding=chunked
    详见 https://zh.wikipedia.org/wiki/%E5%88%86%E5%9D%97%E4%BC%A0%E8%BE%93%E7%BC%96%E7%A0%81
    qgy18
        5
    qgy18  
       2016-02-06 19:37:01 +08:00 via iPhone
    不得不安利一下我的这篇文章:
    https://imququ.com/post/transfer-encoding-header-in-http.html
    KyL
        6
    KyL  
    OP
       2016-02-06 19:39:07 +08:00 via Android
    @rcmerci 所以我设想的是半关闭,不能再写了,但是可以读吧?
    另外, HTTP Request 中除了结尾之外,还有其他地方有两个\n 吗?比如 header 和 body 之间?
    rcmerci
        7
    rcmerci  
       2016-02-06 19:48:08 +08:00
    @KyL 啊啊啊。。之前打错字了,是 header 结尾 2 个\n ,不是 request ,另外就像其他几位说的,根据 content-length (或者有其他什么字段吧) 来确定 request 有没有读完。
    wowpanda
        8
    wowpanda  
       2016-02-06 19:49:49 +08:00 via Android
    返回 0 呀
    wowpanda
        9
    wowpanda  
       2016-02-06 19:52:10 +08:00 via Android
    再配合 content-length
    KyL
        10
    KyL  
    OP
       2016-02-06 19:59:20 +08:00 via Android
    @wowpanda 浏览器不关闭 socket ,服务器 read 怎么会返回 0 呢?
    KyL
        11
    KyL  
    OP
       2016-02-06 20:04:42 +08:00 via Android
    @qgy18 拜读了,对从服务器发送到浏览器解释的很详细。那么从浏览器发送到服务器的持久化连接就只能靠 content-length 来实现吗?还是也可以用 chunked 来实现?
    Strikeactor
        12
    Strikeactor  
       2016-02-06 20:04:43 +08:00
    不是判断它是不是完了的问题,他既然说了 Keep-alive 就表示“后边还有”, socket 在超时被关闭以前都可能还有东西进来
    至于判断一个 HTTP Request 是不是完了,那是 HTTP 协议的事情,跟你 socket 的 read 读不读 0 是没有关系的
    qgy18
        13
    qgy18  
       2016-02-06 20:42:04 +08:00
    @KyL 应该也是可以的,但是浏览器发送的数据一开始很容易得到 Content-Length ,没必要 chunked 啊。
    wowpanda
        14
    wowpanda  
       2016-02-06 20:59:30 +08:00
    @KyL 额,返回 0 又不是非得关闭 socket 好不,写完一次数据就返回 0 ,至于 request 的所有长度是多少,那你得 read 一次之后就去计算一下已经 read 的数据总量是不是等于 content_length 。
    read 返回 0 ,这表示要么 socket 关闭,要么是一次 send 的数据读完,也就是遇到了 EOF 。
    wowpanda
        15
    wowpanda  
       2016-02-06 21:01:26 +08:00
    写完一次数据->读完
    KyL
        16
    KyL  
    OP
       2016-02-07 10:01:11 +08:00 via Android
    @wowpanda read 怎么会返回 0 呢。要么阻塞要么返回负值,只有对面关 socket 才会返回 0 吧?难道我记错了?
    KyL
        17
    KyL  
    OP
       2016-02-07 10:06:12 +08:00 via Android
    我目前在写一个 http server 。一开始打算先把 Request 都读出来,然后再解析 http 。但是有 keep-alive 后,看来就必须边读边解析了。这样 socket IO 代码就和 http 代码混在一起了。不知道 Apache 、 ngnix 都是怎么实现的。
    denghongcai
        18
    denghongcai  
       2016-02-07 16:02:50 +08:00
    @KyL websocket 是先用 http 协议请求升级,然后建立一条新的 TCP 连接,并不是和 http 的连接共用的
    julyclyde
        19
    julyclyde  
       2016-02-18 13:46:23 +08:00
    RFC 里写的明白
    开启 Keep-Alive 时,必须启用 Content-Length 或者 Transfer-Encoding:chunked ,后两者都是可以明确表达长度的
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     927 人在线   最高记录 6679 &bsp;     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 22:49 PVG 06:49 LAX 15:49 JFK 18:49
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86