转自:https://www.jianshu.com/p/0e5b946880b4#

HTTP

HTTP的地址格式如下:

http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
协议和host不分大小写
HTTP消息

一个HTTP消息可能是request或者response消息,两种类型的消息都是由开始行(start-line),零个或多个header域,一个表示header域结束的空行(也就是,一个以CRLF为前缀的空行),一个可能为空的消息主体(message-body)。一个合格的HTTP客户端不应该在消息头或者尾添加多余的CRLF,服务端也会忽略这些字符。

header的值不包括任何前导或后续的LWS(线性空白),线性空白可能会出现在域值(filed-value)的第一个非空白字符之前或最后一个非空白字符之后。前导或后续的LWS可能会被移除而不会改变域值的语意。任何出现在filed-content之间的LWS可能会被一个SP(空格)代替。header域的顺序不重要,但建议把常用的header放在前边(协议里这么说的)。

Request消息

RFC2616中这样定义HTTP Request 消息:

Request = Request-Line
*(( general-header
| request-header(跟本次请求相关的一些header)
| entity-header ) CRLF)(跟本次请求相关的一些header)
CRLF
[ message-body ]
用图来表示如下:

一个HTTP的request消息以一个请求行开始,从第二行开始是header,接下来是一个空行,表示header结束,最后是消息体。

请求行的定义如下:

//请求行的定义
Request-Line = Method SP Request-URL SP HTTP-Version CRLF //方法的定义
Method = "OPTIONS" | "GET" | "HEAD" |"POST" |"PUT" |"DELETE" |"TRACE" |"CONNECT" | extension-method //资源地址的定义
Request-URI ="*" | absoluteURI | abs_path | authotity(CONNECT)

Request消息中使用的header可以是general-header或者request-header,request-header(后边会讲解)。其中有一个比较特殊的就是Host,Host会与reuqest Uri一起来作为Request消息的接收者判断请求资源的条件,方法如下:

  1. 如果Request-URI是绝对地址(absoluteURI),这时请求里的主机存在于Request-URI里。任何出现在请求里Host头域值应当被忽略。

  2. 假如Request-URI不是绝对地址(absoluteURI),并且请求包括一个Host头域,则主机由该Host头域值决定。

  3. 假如由规则1或规则2定义的主机是一个无效的主机,则应当以一个400(错误请求)错误消息返回。

Response消息

响应消息跟请求消息几乎一模一样,定义如下:

   Response      = Status-Line
*(( general-header
| response-header
| entity-header ) CRLF)
CRLF
[ message-body ]
例如下图:

可以看到,除了header不使用request-header之外,只有第一行不同,响应消息的第一行是状态行,其中就包含大名鼎鼎的返回码

Status-Line的内容首先是协议的版本号,然后跟着返回码,最后是解释的内容,它们之间各有一个空格分隔,行的末尾以一个回车换行符作为结束。定义如下:

   Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
返回码

返回码是一个3位数,第一位定义的返回码的类别,总共有5个类别,它们是:

  - 1xx: Informational - Request received, continuing process

  - 2xx: Success - The action was successfully received,
understood, and accepted - 3xx: Redirection - Further action must be taken in order to
complete the request - 4xx: Client Error - The request contains bad syntax or cannot
be fulfilled - 5xx: Server Error - The server failed to fulfill an apparently
valid request

RFC2616中接着又给出了一系列返回码的扩展,这些都是我们平时会用到的,但是那些只是示例,HTTP1.1不强制通信各方遵守这些扩展的返回码,通信各方在返回码的实现上只需要遵守以上边定义的这5种类别的定义,意思就是,返回码的第一位要严格按照文档中所述的来,其他的随便定义。

任何人接收到一个不认识的返回码xyz,都可以把它当做x00来对待。对于不认识的返回码的响应消息,不可以缓存。

Header

RFC2616中定义了4种header类型,在通信各方都认可的情况下,请求头可以被扩展的(可信的扩展只能等到协议的版本更新),如果接收者收到了一个不认识的请求头,这个头将会被当做实体头。4种头类型如下:

  1. 通用头(General Header Fields):可用于request,也可用于response的头,但不可作为实体头,只能作为消息的头。

    general-header = Cache-Control            ; Section 14.9
    | Connection ; Section 14.10
    | Date ; Section 14.18
    | Pragma ; Section 14.32
    | Trailer ; Section 14.40
    | Transfer-Encoding ; Section 14.41
    | Upgrade ; Section 14.42
    | Via ; Section 14.45
    | Warning ; Section 14.46
  2. 请求头(Request Header Fields):被请求发起端用来改变请求行为的头。

    request-header = Accept                   ; Section 14.1
    | Accept-Charset ; Section 14.2
    | Accept-Encoding ; Section 14.3
    | Accept-Language ; Section 14.4
    | Authorization ; Section 14.8
    | Expect ; Section 14.20
    | From ; Section 14.22
    | Host ; Section 14.23
    | If-Match ; Section 14.24
    | If-Modified-Since ; Section 14.25
    | If-None-Match ; Section 14.26
    | If-Range ; Section 14.27
    | If-Unmodified-Since ; Section 14.28
    | Max-Forwards ; Section 14.31
    | Proxy-Authorization ; Section 14.34
    | Range ; Section 14.35
    | Referer ; Section 14.36
    | TE ; Section 14.39
    | User-Agent ; Section 14.43
  3. 响应头(Response Header Fields):被服务器用来对资源进行进一步的说明。

    response-header = Accept-Ranges           ; Section 14.5
    | Age ; Section 14.6
    | ETag ; Section 14.19
    | Location ; Section 14.30
    | Proxy-Authenticate ; Section 14.33
    | Retry-After ; Section 14.37
    | Server ; Section 14.38
    | Vary ; Section 14.44
    | WWW-Authenticate ; Section 14.47
  4. 实体头(Entity Header Fields):如果消息带有消息体,实体头用来作为元信息;如果没有消息体,就是为了描述请求的资源的信息。

    entity-header  = Allow                    ; Section 14.7
    | Content-Encoding ; Section 14.11
    | Content-Language ; Section 14.12
    | Content-Length ; Section 14.13
    | Content-Location ; Section 14.14
    | Content-MD5 ; Section 14.15
    | Content-Range ; Section 14.16
    | Content-Type ; Section 14.17
    | Expires ; Section 14.21
    | Last-Modified ; Section 14.29
    | extension-header
消息体(Message Body)和实体主体(Entity Body)

如果有Transfer-Encoding头,那么消息体解码完了就是实体主体,如果没有Transfer-Encoding头,消息体就是实体主体。

   message-body = entity-body
| <entity-body encoded as per Transfer-Encoding>

在request消息中,消息头中含有Content-Length或者Transfer-Encoding,标识会有一个消息体跟在后边。如果请求的方法不应该含有消息体(如OPTION),那么request消息一定不能含有消息体,即使客户端发送过去,服务器也不会读取消息体。

在response消息中,是否存在消息体由请求方法和返回码来共同决定。像1xx,204,304不会带有消息体。

消息体的长度

消息体长度的确定有一下几个规则,它们顺序执行:

  1. 所有不应该返回内容的Response消息都不应该带有任何的消息体,消息会在第一个空行就被认为是终止了。

  2. 如果消息头含有Transfer-Encoding,且它的值不是identity,那么消息体的长度会使用chunked方式解码来确定,直到连接终止。

  3. 如果消息头中有Content-Length,那么它就代表了entity-lengthtransfer-length。如果同时含有Transfer-Encoding,则entity-lengthtransfer-length可能不会相等,那么Content-Length会被忽略。

  4. 如果消息的媒体类型是multipart/byteranges,并且transfer-length也没有指定,那么传输长度由这个媒体自己定义。通常是收发双发定义好了格式, HTTP1.1客户端请求里如果出现Range头域并且带有多个字节范围(byte-range)指示符,这就意味着客户端能解析multipart/byteranges响应。

  5. 如果是Response消息,也可以由服务器来断开连接,作为消息体结束。

从消息体中得到实体主体,它的类型由两个header来定义,Content-TypeContent-Encoding(通常用来做压缩)。如果有实体主体,则必须有Content-Type,如果没有,接收方就需要猜测,猜不出来就是用application/octet-stream

HTTP连接

HTTP1.1的连接默认使用持续连接(persistent connection),持续连接指的是,有时是客户端会需要在短时间内向服务端请求大量的相关的资源,如果不是持续连接,那么每个资源都要建立一个新的连接,HTTP底层使用的是TCP,那么每次都要使用三次握手建立TCP连接,将造成极大的资源浪费。

持续连接可以带来很多的好处:

  1. 使用更少的TCP连接,对通信各方的压力更小。
  2. 可以使用管道(pipeline)来传输信息,这样请求方不需要等待结果就可以发送下一条信息,对于单个的TCP的使用更充分。
  3. 流量更小
  4. 顺序请求的延时更小。
  5. 不需要重新建立TCP连接就可以传送error,关闭连接等信息。

HTTP1.1的服务器使用TCP的流量控制来控制HTTP的流量,HTTP1.1的客户端在收到服务器连接中发过来的error信息,就要马上关闭此链接。关于HTTP连接还有很多细节,之后再详述。

WebSocket

只从RFC发布的时间看来,WebSocket要晚近很多,HTTP 1.1是1999年,WebSocket则是12年之后了。WebSocket协议的开篇就说,本协议的目的是为了解决基于浏览器的程序需要拉取资源时必须发起多个HTTP请求和长时间的轮训的问题……而创建

HTTP协议和WebSocket协议(一)的更多相关文章

  1. HTTP协议和WebSocket协议(二)

    WebSocket WebSocket协议还很年轻,RFC文档相比HTTP的发布时间也很短,它的诞生是为了创建一种「双向通信」的协议,来作为HTTP协议的一个替代者.那么首先看一下它和HTTP(或者H ...

  2. Bytom BIP-32协议和BIP-44协议

    我们知道HD(分层确定性)钱包,基于 BIP-32:多币种和多帐户钱包,基于 BIP-44:最近比原社区的钱包开发者对比原的BIP-32和BIP-44协议有疑问,所以我今天就专门整理了一下该协议的内容 ...

  3. TCP协议和UDP协议基础介绍

    TCP协议和UDP协议区别 标签(空格分隔): TCP,udp TCP的三次握手 TCP被称为可靠的数据传输协议,主要是通过许多机制来实现的其中最主要的就是三次握手的功能,当然,TCP传送数据的机制非 ...

  4. HTTP协议和SOCKS5协议

    HTTP协议和SOCKS5协议 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们平时上网的时候基本上是离不开浏览器的,尤其是搜索资料的时候,那么这个浏览器是如何工作的呢?用的又是 ...

  5. python 全栈开发,Day33(tcp协议和udp协议,互联网协议与osi模型,socket概念,套接字(socket)初使用)

    先来回顾一下昨天的内容 网络编程开发架构 B/S C/S架构网卡 mac地址网段 ip地址 : 表示了一台电脑在网络中的位置 子网掩码 : ip和子网掩码按位与得到网段 网关ip : 内置在路由器中的 ...

  6. http协议和https协议

    内容: 1.http协议介绍 2.https协议介绍 3.http协议和https协议对比 1.http协议介绍 (1)http协议是什么 1 一个传输协议,协议就是双方都遵守的规范. 2 为什么叫超 ...

  7. (1)基于tcp协议的编程模型 (2)tcp协议和udp协议的比较 (3)基于udp协议的编程模型 (4)反射机制

    1.基于tcp协议的编程模型(重中之重)1.1 编程模型服务器: (1)创建ServerSocket类型的对象,并提供端口号: (2)等待客户端的连接请求,调用accept()方法: (3)使用输入输 ...

  8. (1)网络编程的常识 (2)基于tcp协议的编程模型 (3)tcp协议和udp协议的比较 (4)基于udp协议的编程模型

    1.网络编程的常识 目前主流的网络通讯软件有:微信.QQ.YY.陌陌.探探.飞信.阿里旺旺.... 在吗? 1.1 七层网络模型(熟悉) 为了保证数据传递的可靠安全等等,ISO(国际标准委员会组织)将 ...

  9. http协议及http协议和tcp协议的区别

    http是应用层的协议,并且无连接,无状态的协议. http协议的特点: 1.支持c/s模式 2.简单快速:客户端向服务器端传送数据的时候,只需要发送请求方法和路径,请求方法有:post,get,he ...

随机推荐

  1. leetcode377

    public class Solution { private int[] dp; public int CombinationSum4(int[] nums, int target) { dp = ...

  2. CALayer的基本使用

    CALayer需要导入这个框架:#import <QuartzCore/QuartzCore.h> 一.CALayer常用属性 属性 说明 是否支持隐式动画 anchorPoint 和中心 ...

  3. xcode 编译报错“Cannot create __weak reference in file using manual reference counting”解决办法<转>

    http://blog.csdn.net/ouq68/article/details/51003876 解决方法: Please set ‘Weak References in Manual Reta ...

  4. DAY2-python数据类型、字符编码、文件处理

    阅读目录 一.引子 二.数字 三.字符串 四.列表 五.元祖 六.字典 七.集合 八.数据类型总结 九.运算符 十.字符编码 十一.文件处理 一.引子 1 什么是数据? x=10,10是我们要存储的数 ...

  5. Github修改项目显示的语言类型

    //仓库的根目录下创建 .gitattributes 文件,添加以下代码: *.js linguist-language=java *.css linguist-language=java *.htm ...

  6. 关于handler和异步任务

    handler使用流程概要 首先在主线程新建一个handler实例,重写onhandlemessage(Message msg) 方法,对传过来的message进行处理 然后在子线程中完成操作,操作完 ...

  7. HDU 6395(2018多校第7场1010)Sequence

    不久前做过POJ3070,所以知道这题要用矩阵快速幂优化,但是这个题的递推公式中有一项⌊p/n⌋,场上就不会了... 下来才知道要用分块矩阵快速幂,因为⌊p/n⌋最多有2√p块,可以对每一块使用快速幂 ...

  8. 常用linux配置文件

    /etc/hosts:用户IP与域名的对应解析表/etc/sysconfig/network:机器名.网卡启动.网关等配置/etc/fstab:记录开机自动挂载的文件系统/etc/rc.local:开 ...

  9. Flask框架 之 功能详解

    浏览目录 配置文件 路由系统 视图 请求相关 响应 模板渲染 session 闪现 中间件 蓝图(blueprint) 特殊装饰器 配置文件 知识点 给你一个路径 “settings.Foo”,可以找 ...

  10. python中的作用域与名称空间

    python中的名称空间以及作用域分析 从Python解释器开始执行之后,就在内存中开辟一个空间,每当遇到一个变量的时候,就把变量名和值之间对应的关系记录下来,但是当遇到函数定义的时候,解释器只是象征 ...