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 · 4600 次点击
    这是一个创建于 3218 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一般当浏览器发送完 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   ·   实用小工具   ·   1031 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 21:31 · PVG 05:31 · LAX 13:31 · JFK 16:31
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.