??xml version="1.0" encoding="utf-8" standalone="yes"?>精品日韩av,五月天久久综合网,午夜在线电影亚洲一区http://www.aygfsteel.com/yongboy/category/54836.html记录工作/学习的点Ҏ滴?/description>zh-cnWed, 24 Feb 2021 03:32:27 GMTWed, 24 Feb 2021 03:32:27 GMT60Apisix 1.5 升?2.2 t坑备忘http://www.aygfsteel.com/yongboy/archive/2021/02/23/435806.htmlnieyongnieyongTue, 23 Feb 2021 06:57:00 GMThttp://www.aygfsteel.com/yongboy/archive/2021/02/23/435806.htmlhttp://www.aygfsteel.com/yongboy/comments/435806.htmlhttp://www.aygfsteel.com/yongboy/archive/2021/02/23/435806.html#Feedback0http://www.aygfsteel.com/yongboy/comments/commentRss/435806.htmlhttp://www.aygfsteel.com/yongboy/services/trackbacks/435806.html零、前a

U上q行?APISIX ?1.5 版本Q而社区已l发布了 Apisix 2.2Q是时候需要升U到最新版了,能够享受最版本带来的大量的BugFixQ性能增强Q以及新增特性的支持{~

从Apisix 1.5升到Apisix 2.2q程中,不是一帆风的Q中间踩了不坑Q所谓前车之鉴后事之师,q里l大家简单梳理一下我们团队所在具体业务环境下Q升U过E中t的若干坑,以及一些需要避免的若干注意事项{?/p>

下文所说原先版本,皆指Apisix 1.5Q新版则是Apisix 2.2版本?/p>

一、已有服务发现机制无法正常工?/h2>

针对上游Upstream没有使用服务发现的\由来Ԍ本次升没有遇到什么问题?/p>

公司内部U上业务大都ZConsul KV方式实现服务注册和服务发玎ͼ因此我们自行实现了一?consul_kv.lua 模块实现服务发现程?/p>

q在Apisix 1.5下面一切工作正常?/p>

但在Apisix 2.2下面Q就无法直接工作了,原因如下Q?/p>

  • 服务发现配置指o变了
  • 上游对象包含服务发现旉增加字段 discovery_type q行索引

2.1 服务发现配置指o变了

原先q行中仅支持一U服务发现机Ӟ需要配|在 apisix层下面Q?/p>

apisix:
    ......
    discover: consul_kv
    ......    

新版需要直接在config*.yaml文g中顶层层U下q行配置Q可支持多种不同的\由发现机Ӟ如下Q?/p>

discovery:                      # service discovery center
  eureka:
    host:                       # it's possible to define multiple eureka hosts addresses of the same eureka cluster.
      - "http://127.0.0.1:8761"
    prefix: "/eureka/"
    fetch_interval: 30          # default 30s
    weight: 100                 # default weight for node
    timeout:
      connect: 2000             # default 2000ms
      send: 2000                # default 2000ms
      read: 5000

我们有所变通,直接在配|文仉层配|consul_kv多个集群相关参数Q避?discovery 层q深?/p>

 discovery:
    consul_kv: 1
consul_kv:
  servers:
    -
      host: "172.19.5.30"
      port: 8500
    -
      host: "172.19.5.31"
      port: 8500
  prefix: "upstreams"
  timeout:
    connect: 6000
    read: 6000
    wait: 60
  weight: 1
  delay: 5
  connect_type: "long" # long connect
  ......

当然Q这仅仅保证了服务发现模块能够在启动时被正常加蝲?/p>

推荐阅读Q?/p>

2.2 upstream对象新增字段discovery_type

Apisix当前同时支持多种服务发现机制Q这个很赞。对应的代hQ就是需要额外引?discovery_type 字段Q用于烦引可能同时存在的多个服务发现机制?/p>

?Cousul KV方式服务发现ZQ那么需要在已有?upstream 对象中需要添加该字段Q?/p>

"discovery_type" : "consul_kv"

原先的一?code>upstream对象Q仅仅需?service_name 字段属性指定服务发现相兛_址卛_Q?/p>

{
    "id": "d6c1d325-9003-4217-808d-249aaf52168e",
    "name": "grpc_upstream_hello",
    ......
    "service_name": "http://172.19.5.30:8500/v1/kv/upstreams/grpc/grpc_hello",
    "create_time": 1610437522,
    "desc": "demo grpc service",
    "type": "roundrobin"
}

而新版的则需要添?code>discovery_type字段Q表明该service_name 字段对应的具体模块名Uͼ效果如下Q?/p>

{
    "id": "d6c1d325-9003-4217-808d-249aaf52168e",
    "name": "grpc_upstream_hello",
    ......
    "service_name": "http://172.19.5.30:8500/v1/kv/upstreams/grpc/grpc_hello",
    "create_time": 1610437522,
    "desc": "demo grpc service",
    "type": "roundrobin",
    "discovery_type":"consul_kv"
}

后面我们若支持Consul Service或ETCD KV方式服务发现机制Q则会非常弹性和清晰?/p>

调整了配|指令,d上述字段之后Q后端服务发现其实就已经起作用了?/p>

但gRPC代理路由q不会生?#8230;…

二、gRPC当前不支持upstream_id

在我们的pȝ中,上游和\由是需要单独分开理的,因此创徏的HTTP或GRPC路由需要处理支?code>upstream_id的烦引?/p>

q在1.5版本中,grpc路由是没问题的,但到了apisix 2.2版本中,l护?@spacewander 暂时没做支持Q原因是规划grpc路由和dubbo路由处理逻辑于一_更ؓ紧凑。从l护角度我是认可的,但作Z用者来Ԍq就有些不合理了Q直接丢弃了针对以往数据的支持?/p>

作ؓ当前Geek一些方式,?apisix/init.lua 中,最成?Q优雅和成本成反比)修改如下Q找到如下代码:

    -- todo: support upstream id
    api_ctx.matched_upstream = (route.dns_value and
                                route.dns_value.upstream)
                               or route.value.upstream 

直接替换Z面代码即可解决燃眉之急:

    local up_id = route.value.upstream_id
    if up_id then
        local upstreams = core.config.fetch_created_obj("/upstreams")
        if upstreams then
            local upstream = upstreams:get(tostring(up_id))
            if not upstream then
                core.log.error("failed to find upstream by id: " .. up_id)
                return core.response.exit(502)
            end
            if upstream.has_domain then
                local err
                upstream, err = lru_resolved_domain(upstream,
                                                    upstream.modifiedIndex,
                                                    parse_domain_in_up,
                                                    upstream)
                if err then
                    core.log.error("failed to get resolved upstream: ", err)
                    return core.response.exit(500)
                end
            end
            if upstream.value.pass_host then
                api_ctx.pass_host = upstream.value.pass_host
                api_ctx.upstream_host = upstream.value.upstream_host
            end
            core.log.info("parsed upstream: ", core.json.delay_encode(upstream))
            api_ctx.matched_upstream = upstream.dns_value or upstream.value
        end
    else
        api_ctx.matched_upstream = (route.dns_value and
                                route.dns_value.upstream)
                               or route.value.upstream  
    end

三、自定义auth插g需要微?/h2>

新版的apisix auth授权插g支持多个授权插g串行执行Q这个功能也很赞Q但此DD了先前ؓ具体业务定制的授权插件无法正常工作,q时需要微调一下?/p>

原先调用方式Q?/p>

    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
            consumer_conf.conf_version,
            create_consume_cache, consumer_conf)

因ؓ新版?code>lrucache不再提供 plugin 函数Q需要微调一下:

local lrucache = core.lrucache.new({
  type = "plugin",
})
......
    local consumers = lrucache("consumers_key", consumer_conf.conf_version,
        create_consume_cache, consumer_conf)

另一处是Q顺利授权之后,需要赋?code>consumer相关信息Q?/p>

    ctx.consumer = consumer
    ctx.consumer_id = consumer.consumer_id

此时需要替换成如下方式QؓQ可能存在的Q后l的授权插gl箋作用?/p>

consumer_mod.attach_consumer(ctx, consumer, consumer_conf)

更多请参考:apisix/plugins/key-auth.lua 源码?/p>

四、ETCD V2数据q移到V3

q移分ؓ三步Q?/p>

  1. 升U上已有ETCD 3.3.*版本?.4.*Q满x版Apisix的要求,q时ETCD实例同时支持了V2和V3格式数据
  2. q移V2数据到V3
    • 因ؓ数据量不是非常多Q我采取了一个非常简单和原始的方?/li>
    • 使用 etcdctl 完成V2数据到导?/li>
    • 然后使用文本~辑器vim{完成数据的替换Q生成etcdctl v3格式的数据导入命令脚?/li>
    • q行之后V3数据导入脚本Q完成V2到V3的数据导?/li>
  3. 修改V3 /apisix/upstreams 中包含服务注册的数据Q一一d "discovery_type" : "consul_kv"属?/li>

Z以上操作之后Q从而完成了ETCD V2到V3的数据迁UR?/p>

五、启动apisix后发现ETCD V3已有数据无法加蝲

我们在运l层面,使用 /usr/local/openresty/bin/openresty -p /usr/local/apisix -g daemon off; 方式q行|关E序?/p>

q也导_自动忽略了官Ҏ倡的Q?code>apisix start 命o自动提前为ETCD V3初始化的一些键值对内容?/p>

因此Q需要提前ؓETCD V3建立以下键值对内容Q?/p>

Key                         Value
/apisix/routes          :   init_dir
/apisix/upstreams       :   init_dir
/apisix/services        :   init_dir
/apisix/plugins         :   init_dir
/apisix/consumers       :   init_dir
/apisix/node_status     :   init_dir
/apisix/ssl             :   init_dir
/apisix/global_rules    :   init_dir
/apisix/stream_routes   :   init_dir
/apisix/proto           :   init_dir
/apisix/plugin_metadata :   init_dir

不提前徏立的话,׃Dapisix重启后,无法正常加蝲ETCD中已有数据?/p>

其实有一个补救措施,需要修?apisix/init.lua 内容Q找到如下代码:

            if not dir_res.nodes then
                dir_res.nodes = {}
            end

比较geek的行为,使用下面代码替换一下即可完成兼容:

                if dir_res.key then
                    dir_res.nodes = { clone_tab(dir_res) }
                else
                    dir_res.nodes = {}
                end

六、apisix-dashboard的支?/h2>

我们Zapisix-dashboard定制开发了大量的针对公司实际业务非常实用的企业U特性,但也D了无法直接升U到最新版的apisix-dashboard?/p>

因ؓ非常基础的上游和路由没有发生多大改变Q因此这部分升的需求可以忽略?/p>

实际上,只是在提交上游表单时Q包含服务注册信息JSON字符串中需要增?discovery_type 字段和对应值即可完成支持?/p>

七、小l?/h2>

p了一些时间完成了从Apisix 1.5升到Apisix 2.2的行为,虽然有些坑,但整体来Ԍq算利。目前已l上Uƈ全量部vq行Q目前运行良好?/p>

针对q停留在Apisix 1.5的用P新版增加了Control API以及多种服务发现{新Ҏ支持,q是非常值得升的?/p>

升之前Q不妨仔l阅L一个版本的升日志Q地址Q?a >https://github.com/apache/apisix/blob/2.2/CHANGELOG.md Q,然后需要根据具体业务做好兼Ҏ试准备和准备升步骤Q这些都是非常有必要的?/p>

针对我们团队来讲Q升U到最新版Q一斚w降低了版本升U的压力Q另一斚w也能够辅助我们能参与到开源社Z去,挺好~



nieyong 2021-02-23 14:57 发表评论
]]>HTTP API设计W记http://www.aygfsteel.com/yongboy/archive/2018/01/02/433000.htmlnieyongnieyongTue, 02 Jan 2018 12:53:00 GMThttp://www.aygfsteel.com/yongboy/archive/2018/01/02/433000.htmlhttp://www.aygfsteel.com/yongboy/comments/433000.htmlhttp://www.aygfsteel.com/yongboy/archive/2018/01/02/433000.html#Feedback0http://www.aygfsteel.com/yongboy/comments/commentRss/433000.htmlhttp://www.aygfsteel.com/yongboy/services/trackbacks/433000.html前言

最q一D|_要ؓ一个手机终端APPE序从零开始设计一整套HTTP APIQ因为面向的用户很固定,一个新的移动端APP。目前还是项目初期,自然要求一切快速、从Q实用性ؓ丅R?/p>

下面逐一我们是如何设计HTTP APIQ虽然相对大部分言Q没有什么新意,但对我来说很新鲜的。避免忘_着I闲快记录下来?/p>

技术堆栈的选择

PHP嘛?团队内也没几个h熟悉?/p>

JavaQ好几年没有过了,那么复杂的解x案,再加上团队内也没什么h?……

团队使用qLuaQ基于OpenResty构徏qTCP、HTTP|关{,对Lua + Nginxl合非常熟悉Q能够快速的应用在线上环境。再说Lua语法y、简单,一个新手半天就可以基本熟悉Q马上开工?/p>

看来QNginx + Lua是目前最为适合我们的了?/p>

HTTP APIQ需要充分利用HTTP具体操作语义Q来应对具体的业务操作方法。基于此Q没有闭门造RQ我们选择?http://lor.sumory.com/ q么一个小巧的框架Q用于辅助HTTP API的开发开发?/p>

嗯,OpenResty + Lua + LorQ就构成了我们简单技术堆栈?/p>

HTTP API要设?/h2>

HTTP API路径和语?/h3>

每一具体业务逻辑Q直接在URL Path中体现出来。我们要的是单快速,数据l构之间的连接关p,可能的LE化。egQ?/p>

/resource/video/ID

比如用户反馈q一模块Q将使用下面比较固定的\径:

/user/feedback
  • GETQ以用户l度查询反馈的历史列表,可分?
    • curl -X GET http://localhost/user/feedback?page=1
  • POSTQ提交一个反?
    • curl -X POST http://localhost/user/feedback -d "content=hello"
  • DELETEQ删除一个或多个反馈Q参数附加在URL路径中?
    • curl -X DELETE http://localhost/user/feedback?id=1001
  • PUTQ更新评论内?
    • curl -X PUT http://localhost/user/feedback/1234 -d "content=hello2"

用户属性很多,用户늧只是其中一个部分,因此更新늧q一行ؓQHTTP?PATCH Ҏ可更_և的描q部分数据更新的业务需求:

/user/nickname
  • PATCHQ更新用hUͼ늧是用户属性之一Q可以用更轻量U的 PATCH 语义
    • curl -X PATCH http://localhost/user/nickname -d "nickname=hello2"

嗯,同一cȝ资源URL虽然固定了,但HTTP Method呈现了不同的业务逻辑需求?/p>

HTTP API的访问授?/h3>

实际业务HTTP API的访问是需要授权的?/p>

传统的Access Token解决ҎQ有session回话机制Q一般需要结合Web览器,需要写入到Cookie中,或生产一个JSessionID用于标识{。这针对单纯面向Udl端的HTTP API后端来讲Qƈ没有义务dq一的兼容,略显冗余?/p>

另外是 OAUTH 认证了,有整套的认证Ҏq已工业化,很是成熟了,但对我们而言q是太重Q不太适合轻量U的HTTP APIQ不太可能花费太多的_֊d它的q维工作?/p>

最l选择了轻量?Json Web TokenQ非常紧凑,开即用?/p>

最佛_法是把JWT Token攑֜HTTPh头部中,不至于和其它参数hQ?/p>

curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiI2NyIsInV0eXBlIjoxfQ.LjkZYriurTqIpHSMvojNZZ60J0SZHpqN3TNQeEMSPO8" -X GET http://localhost/user/info

下面是一副浏览器D늚一般认证流E,q与HTTP API认证大体一_

JWT的Lua实现Q推? https://github.com/SkyLothar/lua-resty-jwt.gitQ简单够用?/p>

JWT和Lor的结?/h3>

jwt需要和业务q行l定Q结?lor q个API开发框架提供的中间件机Ӟ可在业务处理之前Q在合适位|进行权限拦截?/p>

  • 用户需要请求进行授权接口,比如登陆{?/li>
  • 服务器端会把用户标识W,比如用户id{,存入JWT的payload负荷中,然后生成Token字符Ԍ发给客户?/li>
  • 客户端收到JWT生成的Token字符Ԍ在后l的h中需要附加在HTTPh的Header?/li>
  • 完成认证q程

不同于OAUTHQJWT协议?strong>自包?/strong>Ҏ,军_了后端可以将很多属性信息存攑֜payload负荷中,其token生成之后后端可以不用存储Q下ơ客L发送请求时会发送给服务器端Q后端获取之后,直接验证卛_Q验证通过Q可以直接读取原先保存其中的所有属性?/p>

下面梳理一下Jwt认证和Lor的结合?/p>

  • 全局拦截Q针Ҏ有PATHQ所有HTTP MethodQ这里处理JWT认证Q若认证成功Q会直接把用户id注入到当前业务处理上下文中,后面的业务可以直接读取当前用Lid?/li>
app:use(function(req, res, next)
    local token = ngx.req.get_headers()["Authorization"]
    -- 校验p|Qerr为错误代码,比如 400
    local payload, err = verify_jwt(token)
    if err then
        res:status(err):send("bad access token reqeust")
        return
    end

    -- 注入q当前上下文中,避免每次从token中获?    req.params.uid = payload.uid

    next()
end)
  • 针对具体路径q行讑֮权限拦截Q较_粒度;比如 /user 只允许已登陆授权用户讉K
app:use("/user", function(req, res, next)
    if not req.params.uid then
        -- 注意Q这里没有调用next()ҎQ请求到q里截止了Q不在匹配后面的路由
        res:status(403):send("not allowed reqeust")
    else
        next() -- 满以上条gQ那么l匹配下一个\?    end
end)
  • 一U是较细_度Q具体到每一个API接口Q因然URL一_但不同的HTTP Method有时h权限q是有区别的
local function check_token(req, res, next)
    if not req.params.uid then
        res:status(403):send("not allowed reqeust")
    else
        next()
    end
end

local function check_master(req, res, next)
    if not req.params.uid ~= master_uid then
        res:status(403):send("not allowed reqeust")
    else
        next()
    end
end

local lor = require("lor.index")
local app = lor()

-- 声明一个group router
local user_router = lor:Router()

-- 假设查看是不需要用h限的
user_router:get("/feedback", function(req, res, next)
end)

user_router:put("/feedback", check_token, function(req, res, next)
end)

user_router:post("/feedback", check_token, function(req, res, next)
end)

-- 只有理员才有权限删?user_router:delete("/feedback", check_master, function(req, res, next)
end)

-- 以middleware的Ş式将该group router加蝲q来
app:use("/user", user_router())

......

app:run()

Z么没有选择GraphQL API Q?/h2>

我们在上一个项目中对外提供了GraphQL APIQ其Q在试环境下)自n提供文档输出自托机Ӟ再结合方便的调试客户端,实让后端开发和前端APP开发大大降低了频繁交流的频率,节省了若q流量,但前期还是需要较多的培训投入?/p>

但在新项目中Q一度想提供GraphQL APIQ遇到的问题如下Q?/p>

  • 全新的项目数据结构属性变动太频繁
  • 普遍求快Q业务模型快速开发、调?/li>
  • 大家普遍对GraphQL API有些抵触Q用JSON输出格式的HTTP API是约定俗成的习惯选择

毫无疑问Q以最低成本快速构为完整的APP功能QHTTP API + JSON格式是最服的选择?/p>

虽然有些担心服务器端的输出,很多时候还是会费掉一些流量,客户端ƈ不能够有效的利用q回数据的所有字D属性。但和进度以及h们已l习惯的HTTP API调用方式相比Q又微乎其微了?/p>

当前q一套HTTP API技术堆栈运行的q不错,希望能给有同样需要的同学提供一点点的参考h? :))

当然没有一成不变的架构模型Q随着业务的逐渐发展Q后面相信会有很多的变动。但q是以后的事情了Q谁知道呢,后面有空再次记录吧~



nieyong 2018-01-02 20:53 发表评论
]]>
HTTP/2W记之错误处理和安全http://www.aygfsteel.com/yongboy/archive/2015/03/24/423791.htmlnieyongnieyongTue, 24 Mar 2015 07:27:00 GMThttp://www.aygfsteel.com/yongboy/archive/2015/03/24/423791.htmlhttp://www.aygfsteel.com/yongboy/comments/423791.htmlhttp://www.aygfsteel.com/yongboy/archive/2015/03/24/423791.html#Feedback0http://www.aygfsteel.com/yongboy/comments/commentRss/423791.htmlhttp://www.aygfsteel.com/yongboy/services/trackbacks/423791.html

零。前a

q里整理了一下错误和安全相关部分单记录?/p>

一。HTTP/2错误

1. 错误定义

HTTP/2定义了两U类型错误:

  • D整个q接不可使用的错误ؓq接错误(connection error)
  • 单独出现在单个连接上的错误ؓ错?stream error)

2. 错误代码

错误代码Q?2位正整数表示错误原因QRST_STREAM和GOAWAY帧中包含?/p>

未知或不支持的错误代码可以选择忽略Q或作ؓINTERNAL_ERROR错误对待都可以?/p>

3. q接错误处理

一般来讲连接错误很严重Q会D处理q程无法q行下去Q或影响到整个连接的状态?/p>

  • l端一旦遇上连接错误,需W一旉在最后一个可用流上发送包含错误原因GOAWAY帧过去,然后关闭q接
  • GOAWAY有可能不被对端成功接收到Q若成功接收可获得连接被l止的原?
  • l端可在M旉l止q接Q也可以把流错误作ؓq接错误对待。但都应该在关闭q接之前发送一个GOAWAY帧告知对?

4. 错?/h4>

一般来讲具体流上的错误不会媄响到其它的处理?/p>

  • l端到错误,需要发送一个RST_STREAM帧,其包含了操作到错误流标识W?
  • RST_STREAM应当是发送错误流最后一个Q内含错误原因?
  • 发送方在发送之后,需要准备接收对端将要或卛_发送过来的帧数据,处理方式是忽略之,除非是可以修改连接状态
  • 一般来Ԍl端不应该发送多个RST_STREAM帧,但若在一个往q时间之后已关闭的流上能够l接收Q则需要发送再ơ发送一个RST_STREAM帧,处理q种行ؓ不端的实现?
  • l端在接收到RST_STREAM帧之后,不能响应一个RST_STREAM帧,避免d@?

5. q接l止

TCPq接被关闭或重置时仍有处?open"?half closed"的流不能自动重试?/p>

二。HTTP/2安全注意事项

1. 跨协议攻?/h4>

跨协议攻击,字面上理解就很简单,比如d者构建HTTP/1.1h直接转发l仅仅支持HTTP/2的服务器Q以期待获取d效果?/p>

q里有一讲解跨协议d的文章:http://www.freebuf.com/articles/web/19622.html

TLS的加密机制得攻击者很难获得明文,另外TLS的ALPN协议扩展可以很轻村֤理请求是否需要作为HTTP/2hq行处理QM可有效阻止对ZTLS的其它协议攻凅R?/p>

Z标准版TCP没有TLS和ALPN的帮忙,客户端所发送连接序a前缀为PRI字符串用来؜淆HTTP/1.1服务器,但对其它协议没有提供保护Q仅限于此。但在处理时Q若接收到HTTP/1.1的请求,没有包含Upgrade升字段Q则需要认为是一个跨协议d?/p>

MQ程序要可能的健壮Q容错,针对非法的请求,直接关闭Ҏq接?/p>

2. 中介端数据{换封装的d

中介所做的HTTP/1.1和HTTP/2之间转换Q会存在d点:

  1. HTTP/2头字D名U编码允怋用HTTP/1.1没有使用到的头字D名Uͼ中介在{换HTTP/2到HTTP/1.1时就Ҏ出现包含非法h头字DHTTP/1.1数据?
  2. HTTP/2允许头字D值可以是非法|诸如回R(CR, ASCII 0xd), 换行 (LF, ASCII 0xa), 零字W?(NUL, ASCII 0x0)Q这在逐字解析实现时是一个风险?

解决方式Q一旦发现非法头字段名称Q以及非法头字段|都作Z完整、残~数据对待,或丢弃,或忽略?/p>

3. 推送内容的~存

推送内Ҏ保证的服务器提供Q是否缓存由头字DCache-Control控制?/p>

但若服务器上多租户Ş式(SAASQ,每一个租户用一部分URLI间Q比?tenant1.domain.comQtenant2.domain.comQ服务器需要确保没有授权的U户不能够推送超于预期的资源Q覆盖已有内宏V?/p>

原始服务器没有被授权使用推送,既不能够q规发送推送,也不能够被缓存?/p>

4. 拒绝服务d注意事项

  • HTTP/2因ؓ要ؓ、报头压~、流量控制等Ҏ占用资源较多,因此针对每一个连接的内存分配要设|限额,否则很少的连接占满内存,无法正常服务
  • 针对单个q接Q规范对PUSH_PROMISE帧数量没有约束,但客L需要设|一个上限|q也是确定需要维护的"reserved (remote)"状态的数量Q超出限额需要报ENHANCE_YOUR_CALMcd错?
  • SETTINGS帧有可能会被滥用D对端需要花Ҏ间解析处理设|限制等Q滥用情况包括包含未定义的参敎ͼ以及同一个参数多ơ出现等Q类gWINDOW_UPDATE和PRIORITY帧都会存在滥用的情况Q这些被滥用导致资源耗费情况严重
  • 大量或空帧一样会被滥用,但又W合逻辑Q耗费服务器资源在处理报文头部上面。比如空负蝲DATA帧,以及用于携带报文头部数据的CONTINUATION帧,都属于安全隐?
  • 报头压羃存在潜在风险Q也会被滥用Q详情可参考HPACK协议W七章:http://http2.github.io/http2-spec/compression.html#Security
  • l端中途发送的SETTINGS帧所定义参数不是立即可以生效的,q会D对端在实际操作时可能会超q最新的限制。徏议直接在q接建立时在q接序言内包含设||q如此Q客L也会存在出服务器端q接序言中所讄的最新限定倹{?

MQ诸如SETTINGS帧、小帧或IQ报头压~被合理滥用Ӟ表明上看W合逻辑Q会造成资源q度消耗。这需要服务器端监控跟t到此种行ؓQƈ且设|用数量的上限Q一旦发现直接报ENHANCE_YOUR_CALMcdq接错误?/p>

5. 报头块大限?/h4>

报头块过大导致实现需要维护大量的状态开销。另外,Ҏ报头字段q行路由的情况,若此报头字段出现在一pd报头块的最后一个里面Q可能会D无法正常路由到目的地。若被缓存会D耗费大量的内存。这需要设|SETTINGS_MAX_HEADER_LIST_SIZE参数限制报头最大|以尽可能的避免出C上情c?/p>

服务器一旦接收到过报头限制hQ需要响应一?31Q请求头q大Q?HTTP状态码Q客L呢可直接丢掉响应?/p>

6. 压羃使用的安全隐?/h4>
  • 针对安全通道Q不能用同一个压~字典压~保密的关键数据和易受攻击者控制的数据
  • 来源数据不能定为完全可靠,׃应该使用压羃机制
  • 通用的压羃不能在基于TLS的HTTP/2上用这一部分Q可参?http://http2.github.io/http2-spec/compression.html#Security

7. 填充使用的安全隐?/h4>

一般来Ԍ填充可用来؜淆的真实负载长度,E加保护Q降低攻ȝ可能性。但若不当的填充{略Q固定填充数、可L推导出填充规则等情况都会降低保护的力度,都有可能会被d者破解?/p>

中介讑֤应该保留DATA帧的填充Q需要避免如上所qC些情况)Q但可丢弃HEADERS和PUSH_PROMISE帧的填充?/p>

三。TLS

HTTP/2加密建立在TLS基础Q关于TLSQ维基百U上有解释:http://zh.wikipedia.org/wiki/%E5%82%B3%E8%BC%B8%E5%B1%A4%E5%AE%89%E5%85%A8%E5%8D%94%E8%AD%B0

摘取一张图Q可说明ZALPN协议扩展定义的协商流E:

其它要求Q?/p>

  • 只能ZTLS >= 1.2版本。目前TLS 1.3案版本,正式版本目前未可知。目前只有TLS 1.2可选?
  • 必须支持Server Name Indication (SNI) [TLS-EXT]扩展Q客L在连接协商阶D需要携带上域名
  • ZTLS 1.3或更高版本构建,仅需要支持SNI扩展。TLS 1.2要求较多
  • ZTLS 1.2构徏
    • 必须用压羃机制。不恰当压羃机制会导致信息外ԌHTTP/2报头有压~机?
    • 必须用重新协商机制。终端对待TLS 1.2重新协商作ؓPROTOCOL_ERRORcdq接错误对待Q密码套件加密次数限制导致连接一直挂L待不可用
    • l端可以通过重新协商提供对客L凭证保护功能在握手期_重新协商必须发生在发送连接序a之前q行。服务器当看到重新协商请求时应该h客户端证书在q接建立?
    • 当客Lh受保护的特定资源Ӟ服务器可以响应HTTP_1_1_REQUIRED错误Q可有效L重新协商机制

四。小l?/h3>

q里单记录HTTP/2错误和安全相关事,本系列规范学习到此告一D落?/p>

nieyong 2015-03-24 15:27 发表评论
]]>HTTP/2W记之消息交?/title><link>http://www.aygfsteel.com/yongboy/archive/2015/03/23/423751.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Mon, 23 Mar 2015 08:45:00 GMT</pubDate><guid>http://www.aygfsteel.com/yongboy/archive/2015/03/23/423751.html</guid><wfw:comment>http://www.aygfsteel.com/yongboy/comments/423751.html</wfw:comment><comments>http://www.aygfsteel.com/yongboy/archive/2015/03/23/423751.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/yongboy/comments/commentRss/423751.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/yongboy/services/trackbacks/423751.html</trackback:ping><description><![CDATA[<div id="wmqeeuq" class="wrap"><h3 id="-">前言</h3> <p>无论是HTTP/1.*q是HTTP/2QHTTP的基本语义是不变的,比如Ҏ语义QGET/PUST/PUT/DELETEQ,状态码Q?00/404/500{)QRange RequestQCacheingQAuthentication、URL路径。以前纯文本形式作ؓ传输的蝲体,HTTP/2带来了与之不同的二进制传输语法语义?/p> <p>下面为HTTP/2消息交换方便W记?/p> <h3 id="-">h/响应程</h3> <p>一个典型的HTTP消息包含h/响应Q组成如下:</p> <ul> <li>以响应ؓ例,零或多个HEADERS帧(每一个HEADERS帧可能跟着>=0个CONTINUATION帧,以补充单个HEADERS定w不够的情况)包含状态码?xx的报文头响应</li> <li>或者一个HEADERS帧包含了完整的报文头Q一般情况下Q?/li> <li>零个或多个DATA数据帧包含了具体的消息负载内?/li> <li>一个HEADERS帧,后面跟随零个或多个包含有报尾Qtrailer-partQ的CONTINUATION帧,作ؓ可选项</li> </ul> <p>注意事项Q?/p> <ul> <li>一个HEADERS帧携带有END_STREAM标志Q后面可跟随有CONTINUATION帧用以补充剩余的包头?/li> <li>来自于其它流的类型是不能够出现在HEADERS帧和CONTINUATION帧中?/li> <li>DATA数据帧不支持分块传输~码Qchunked transfer encodingQ?/li> <li>报尾字段QTrailing header fieldQ当出现在报头块中时Q可以终止当前流</li> <li>HEADERS帧以及关联的CONTINUATION帧只能够出现在一个流的开始或l束?/li> <li>HTTPh-相应交换消耗一个流Q请求准备HEADERS帧打开,h的包含有END_STREAM标志D两端处于半关闭状?half closed(local/server)Q响应一个HEADERS帧,若某响应帧包含有END_STREAM标志Q流被关闭</li> <li>一个HTTP响应完成指的响应帧是包含有END_STREAM标志Q在服务器发送ƈ且客L接收成功。若响应不依赖于客户端的hQ服务器端可以在先于客户端发送请求之前发送完成,之后服务器通过再次发送一个RST_STREAM(错误代码为NO_ERRORQ请求客L攑ּ发送请求。这要求客户端在接收到RST_STREAM帧后必须不能够丢弃响应,无论是处于什么}慎原因?/li> </ul> <h4 id="1-">1. 不支持升U机</h4> <p>HTTP/2多\复用Q以及自w也可以通过HTTP/1.1 101切换古来Q因此不支持101切换协议QSwitching ProtocolsQ机制也是情理之中?/p> <h4 id="2-http-header-fields">2. HTTP Header Fields</h4> <p>HTTP/2报头字段注意点:</p> <ol> <li>和HTTP/1.x报头字段一P都是ASCII字符表示</li> <li>字段要求全部写Q?Accept" -> "accept"</li> <li>若大写,会被作ؓ不完整数据对待,有被丢弃的风?/li> <li>新增伪报头字D,但不属于常规HTTP头部字段Q不允许l端自己产生Q只允许规范中所定义??ul> <li>:method</li> <li>:scheme</li> <li>:authority</li> <li>:path</li> <li>:status</li> </ul> </li> <li>伪报头字D必d现在常规HTTP报头字段之前</li> <li>q接属性专用字D(Connection-Specific Header FieldsQ不再被使用Q但Transfer-Encoding可以允许出现在请求头中)Q比如Keep-Alive, Proxy-Connection, Transfer-Encoding和Upgrade{?/li> </ol> <h4 id="3-">3. 单示?/h4> <p>单图片请求:</p> <p><img src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/5264ea818301_D4ED/image_thumb_15.png" alt="" /></p> <p>模拟一ơ提交,讄报头大于16KBQ一般情况下Q报头没有那么大Q除非Cookie撑大Q:</p> <p><img src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/5264ea818301_D4ED/image_thumb_18.png" alt="" /></p> <p>以上CZQ可以帮助理解HTTP/1.x和HTTP/2在HTTP语义表述上的不同?/p> <h4 id="4-">4. 可靠性机?/h4> <p>HTTP/1.1QHTTP客户端无法重试非q等hQ尤其在错误发生的时候,׃无法错误性质q会寚w试带来不利的影响?/p> <p>而HTTP/2在这斚w有所增强Q提供了两种方式可判断请求是否被完成Q?/p> <ul> <li>GOAWAY帧会携带上流标识W的最大|低于此值的h已经被执行过Q高于此值的h帧,则可以再ơ放心重?/li> <li>包含有REFUSED_STREAM错误代码的RST_STREAM帧说明当前流早于M处理发生之前已l被关闭Q因此发生在当前上的请求可以安全重试?/li> </ul> <p>另外PING帧有利于客户端检当前连接是否可用,可以理解为心跳保zLӞ因ؓ一些网兟뀁负载设备会关闭I闲状态下的连接以节省资源?/p> <h3 id="-">服务器推送机?/h3> <p>HTTP/2新增Ҏ,服务器根据客L一ơ请求内容主动推送与之相关的hq去Q避免客L在解析出初次h面内容Ӟ再逐一发送资源请求,节省|络资源利用效率?一些注意事:</p> <ul> <li>客户端可以通过讄SETTINGS_ENABLE_PUSH?值通知服务器端用推?/li> <li>承诺h应该是可~存、安全,q且不能够携带请求的负蝲内容Q这需要客L做检?/li> <li>推送的响应若不可缓存,客户端不能作为HTTP cache存储Q这对单独的非浏览器环境特别适合</li> <li>服务器必d含一?code>:authority</code>伪头部字D,标明自n被授权。客L若检不到需要作为PROTOCOL_ERRORcd错误对?/li> <li>中介讑֤接收到服务器的推送后Q可以决定是否要转发l客LQ中介可以单独选择推送内容发送给客户端。这是一个特别需要注意的?/li> <li>客户端必Ll来自服务器端的对SETTINGS_ENABLE_PUSH属性非0值的修改Q也是说服务器不能要求客户端打开PUSH开养I客户端一旦遇到需要响应PROTOCOL_ERRORcdq接错误</li> <li>客户端不能够发送推送,PUSH_PROMISE帧只能够来自于服务器端(作ؓ推送请求者发送)Q否则将会作为PROTOCOL_ERRORcd的连接错误对?/li> <li>PUSH_PROMISE需要包含伪头部:methodQ若客户端认Z安全Q必d应一个PROTOCOL_ERRORcd错?/li> <li>服务器端应该可能早的发送PUSH_PROMISE帧,以避免与来自客户端对相同资源的请求两者生冲H?/li> <li>发送PUSH_PROMISE帧会创徏一个新的流Q然后处于两端的保留状态,reserved (local/remote)</li> <li>发送完PUSH_PROMISE帧,服务器需要马上发送具体DATA数据?/li> <li>客户端接收完PUSH_PROMISE帧后Q选择接收PUSH响应内容Q这期间不能触发h承诺的响应内容,直到承诺关?/li> <li>客户端不需要接收推送内ҎQ可以选择发送RST_STREAM帧,包含CANCEL/REFUSED_STREAM代码Q以及PUSH标识符发送给服务器端Q重|推送流</li> <li>客户端可以通过讄SETTINGS_MAX_CONCURRENT_STREAMS限制响应敎ͼgؓ0用。但不能L服务器发送PUSH_PROMISE?/li> </ul> <p>比如Q服务器接收到来自客L的请求某个HTML文档资源Q该文档包含了若q图片连接,服务器应该优先发送图片数据到客户端,q需要优先发送推送承诺早于包含完整HTML文档内容的DATA帧,q样客户端优先接收到承诺资源Q后面接收到DATA数据帧进行解析出囄q接的时候,避免再ơ发送图片资源请求嘛?/p> <h3 id="connect-">CONNECTҎ</h3> <p>在HTTP原始语义中是没有CONNECTҎ的,q个伪方法(pseudo-methodQ在HTTP/1.xQHTTP代理用作转换HTTPq接通过隧洞方式到远E主机,HTTPS方式交互?HTTP/2与之cMQ伪ҎCONNECT被HTTP代理用作在一个单独的HTTP/2之上徏立一个到q程L的隧道,要求如下Q?/p> <ul> <li>:method=CONNECT</li> <li>":scheme"?:path"被省?/li> <li>":authority"字段Z理要q接的远E主机和端口信息</li> </ul> <p>一旦不满要求Q会被视Z完整的需求?/p> <ul> <li>q接成功建立Q代理发送给客户端一?xx的状态码</li> <li>代理两端在HEADERS帧都发送完毕后Q后l的DATA帧开始发?/li> <li>代理转发客户端发送的DATA数据帧到q程服务?/li> <li>代理接收到服务器数据l装成DATA数据?/li> <li>非DATAcd数据帧,包括管理类型的RST_STREAM、WINDOW_UPDATE、PRIORITY帧都是不能够在已l连接的上发送的Q否则会被当做流错误对待</li> <li>客户端接收到包含有END_STREAM标志位的DATA帧时Q尽量也要发送一个包含有END_STREAM标志位的DATA?/li> <li>DATA帧END_STREAM标志位被当做TCP FIN比特标志对待Q?ul> <li>代理接收到DATA帧带有END_STREAM标志位,在{发时会设|TCP FIN比特?/li> <li>代理接收到TCPD包含有FIN比特位设|时Q会转发一个DATA帧ƈ携带END_STREAM标志?/li> <li>最后的TCPD|DATA帧可以ؓI?/li> </ul> </li> <li>TCPq接错误以RST_STREAM帧关?/li> <li>代理对待在TCPq接中出现的错误Q包括接收到一个包含有RST比特位的TCPD,作ؓCONNECT_ERRORcd的流错误抛出</li> <li>一旦检到或HTTP/2q接的错误,代理必须发送一个TCPDƈ且其RST标志被设|?/li> <li>代理不能仅仅依靠SETTINGS_MAX_CONCURRENT_STREAMS属性D行限制资源消?/li> </ul> <h3 id="-">持久q接和重?/h3> <p>HTTP/2消息交换通过持久q接、重用实玎ͼ目的可能做到资源利用率最大化?/p> <ol> <li>HTTP/2为持久性连接,Z性能原因Q规范徏议客L不要关闭已有q接除非不再需要和服务器保持通信。服务器端要是主动关闭连接的话,在请求量大的情况下,会导致系l出现大量的TIME_WAIT状态TCPQ每一个TIME_WAIT状态默认情况下臛_持箋60U,特别占用pȝ资源。因此最佛_跉|客户端主动关闭连接,避免Linux服务器端出现TIME_WAIT?/li> <li>Z具体L和端口,客户端应该只打开一个HTTP/2q接</li> <li>客户端可以额外创接作为替代补充:替换已耗尽可用标识符Q或hTLSq接Q或替换遇到错误的连?/li> <li>当Q一端想关闭q接的时候,都应该第一旉发送一个GOAWAY帧到对端Q告知对方先前发送的帧已l被处理q,l止之后的一些剩余Q务,l止可放心关?/li> <li>有一些情冉|务器若不希望客户端重用连接,可返?21 (Misdirected Request) 状态码作ؓ响应Q默认可~存QPOSTҎ或cache-control可控ӞQ但代理不能够ؓ客户端请求生?21状态码?/li> <li>HTTP代理与每一个服务器之间可以可能保持一个持久的q接方便专递客L的请求;客户端到代理之间可以所有请求共享、重用一个连?/li> </ol> <h3 id="-">结</h3> <p>以上为HTTP/2消息交换机制的一些简单梳理,需要注意点Q?/p> <ol> <li>HTTP/2不允怋用连接特定头部字D?/li> <li>新增?个头?/li> <li>推送机制的一些特性需?/li> <li>RST_STREAM{标志位的使用</li> </ol> </div><img src ="http://www.aygfsteel.com/yongboy/aggbug/423751.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/yongboy/" target="_blank">nieyong</a> 2015-03-23 16:45 <a href="http://www.aygfsteel.com/yongboy/archive/2015/03/23/423751.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HTTP/2W记之http://www.aygfsteel.com/yongboy/archive/2015/03/20/423655.htmlnieyongnieyongFri, 20 Mar 2015 01:24:00 GMThttp://www.aygfsteel.com/yongboy/archive/2015/03/20/423655.htmlhttp://www.aygfsteel.com/yongboy/comments/423655.htmlhttp://www.aygfsteel.com/yongboy/archive/2015/03/20/423655.html#Feedback0http://www.aygfsteel.com/yongboy/comments/commentRss/423655.htmlhttp://www.aygfsteel.com/yongboy/services/trackbacks/423655.html

零。前a

客户端和服务器端一旦握手协商成功接建立q接Q端点之间可以基于HTTP/2协议传递交换数据了?/p>

一。通用格式

下图为HTTP/2帧通用格式Q?负蝲的比特位通用l构Q?/p>

+-----------------------------------------------+
|                Length (24)                    |
+---------------+---------------+---------------+
|  Type (8)     |  Flags (8)    |
+-+-------------+---------------+-------------------------------+
|R|                Stream Identifier (31)                       |
+=+=============================================================+
|                  Frame Payload (0...)                       ...
+---------------------------------------------------------------+

帧头为固定的9个字节((24+8+8+1+31)/8=9Q呈玎ͼ变化的ؓ帧的负蝲(payload)Q负载内Ҏ由cdQTypeQ定义?/p>

  • 帧长度LengthQ无W号的自然数Q?4个比特表C,仅表C负蝲所占用字节敎ͼ不包括头所占用?个字节。默认大区间ؓ?~16,384(2^14)Q一旦超q默认最大?^14(16384)Q发送方不再允许发送,除非接收到接收方定义的SETTINGS_MAX_FRAME_SIZEQ一般此值区间ؓ2^14 ~ 2^24Q值的通知?
  • 帧类型TypeQ?个比特表C,定义了负蝲的具体格式和帧的语义QHTTP/2规范定义?0个cdQ这里不包括实验cd帧和扩展cd?
  • 帧的标志位FlagsQ?个比特表C,服务于具体cdQ默认gؓ0x0。有一个小技巧需要注意,一般来Ԍ8个比特可以容U?个不同的标志Q比如,PADDEDgؓ0x8Q二q制表示?0001000QEND_HEADERSgؓ0x4Q二q制表示?0000100QEND_STREAMgؓ0X1Q二q制?0000001。可以同时在一个字节中传达三种标志位,二进制表CZؓ00001101Q即0x13。因此,后面的l构中,标志位一般会使用8个比特表C,若某位不定Q用问?替代Q表C此处可能会被设|标志位
  • 帧保留比特ؓRQ在HTTP/2语境下ؓ保留的比特位Q固定gؓ0X0
  • 标识符Stream IdentifierQ无W号?1比特表示无符可然数?x0DCZؓ帧仅作用于连接,不隶属于单独的流?

关于帧长度,需要稍加关注: - 0 ~ 2^14Q?6384Qؓ默认U定长度Q所有端炚w需要遵?- 2^14 (16,384) ~ 2^24-1(16,777,215)此区间数|需要接收方讄SETTINGS_MAX_FRAME_SIZE参数单独赋?- 一端接收到的长度过讑֮上限或太小Q需要发送FRAME_SIZE_ERR错误 - 当镉K误会影响到整个连接状态时Q须以连接错误对待之Q比如HEADERSQPUSH_PROMISEQCONTINUATIONQSETTINGSQ以及标识W不该ؓ0的{,都需要如此处?- M端都没有义务必须使用完一个的所有可用空?- 大可能会导致gq,针对旉敏感的Q比如RST_STREAM, WINDOW_UPDATE, PRIORITYQ需要快速发送出去,以免延迟D性能{问?/p>

二。报文头压羃和解?/h3>

和HTTP/1一PHTTP/2报头字段包含一个或多个相关的键值对。报头字D会在HTTPh/响应报头和服务器推送操作中使用。原先ؓ文本字段Q现在需要用HTTP报头压羃q行序列化成报头分块Q作为HEADERS ?PUSH_PROMISE、CONTINUATION{的负载传输出厅R?/p>

解压~采用的HPACK协议Q具体可参考:http://http2.github.com/http2-spec/compression.html

接收端合q接收到的l装成报头分块,解压~还原报头集合?/p>

一个完整的报头分块包含Q?- 单个包含报头l止标记END_HEADERS的HEADERS、PUSH_PROMISE帧,或?- HEADERS、PUSH_PROMISE帧不包含的END_HEADERS标记Q后l跟随一个或多个CONTINUATION帧,最后一个CONTINUATION帧包含了END_HEADERS标记?/p>

报头压羃是有状态的Q在一个完整的q接中,一方的压羃上下文环境,另一方的解压的上下文环境Q都是需要具备的。报头解码失败需要作接错误COMPRESSION_ERROR对待?/p>

报头块彼此之间离散,作ؓq箋的同一cd帧序列存在,不存在交错以及来自其他cd帧或。D一个例子,一个连l的HEADERS/CONTINUATION/PUSH_PROMISE帧序列,最后一个包含了END_HEADERS标记Q表CZ个报头完l。一个报头块逻辑上是一个Q但是否完整取决于同cdq箋的的最后一个包含END_HEADERS标记?/p>

报头块作为HEADERS/PUSH_PROMISE/CONTINUATION{负蝲被一端发向另一端。接收端需要从HEADERS/PUSH_PROMISE/CONTINUATION{负蝲中进行组装报头块Q执行解压还原报头集合,不管帧需要不需要被丢弃。接收端在解压时若不能够正常解压报头块,需要回应COMPRESSION_ERROR错误Q然后终止连接?/p>

三。HTTP/2定义的

规范定义?0个正式用到帧类型,扩展实验cd的ALTSVC、BLOCKED{不在介l之列。下面按照优先用顺序重新排排序?/p>

1. SETTINGS

+-----------------------------------------------+
|                Length (24)                    |
+---------------+---------------+---------------+
|     0x4 (8)   | 0000 000? (8) |
+-+-------------+---------------+-------------------------------+
|R|                Stream Identifier/0x0 (32)                   |
+=+=============================+===============================+
|       Identifier (16)         |
+-------------------------------+-------------------------------+
|                        Value (32)                             |
+---------------------------------------------------------------+
|       Identifier (16)         |
+-------------------------------+-------------------------------+
|                        Value (32)                             |
+---------------------------------------------------------------+  

讄帧,接收者向发送者通告己方讑֮Q服务器端在q接成功后必ȝ一个发送的帧?/p>

字段Identifier定义了如下参敎ͼ - SETTINGS_HEADER_TABLE_SIZE (0x1)Q通知接收者报头表的字节数最大|报头块解码用;初始gؓ4096个字节,默认可不用设|?- SETTINGS_ENABLE_PUSH (0x2)Q?Q禁止服务器推送,1Q允许推送;其它值非法,PROTOCOL_ERROR错误 - SETTINGS_MAX_CONCURRENT_STREAMS (0x3)Q发送者允许可打开的最大|?00Q默认可不用讄Q?gؓ止创徏新流 - SETTINGS_INITIAL_WINDOW_SIZE (0x4)Q发送端控H口大小Q默认?^16-1 (65,535)个字节大;最大gؓ2^31-1个字节大,若溢出需要报FLOW_CONTROL_ERROR错误 - SETTINGS_MAX_FRAME_SIZE (0x5)Q单帧负载最大|默认?^14Q?6384Q个字节Q两端所发送都会收到此设定媄响;值区间ؓ2^14Q?6384Q?2^24-1(16777215) - SETTINGS_MAX_HEADER_LIST_SIZE (0x6)Q发送端通告自己准备接收的报头集合最大|卛_节数。此g赖于未压~报头字D,包含字段名称、字Dg及每一个报头字D늚32个字节的开销{;文档里面虽说默认g受限Ӟ因ؓ受到报头集合大小不限制的影响Q个Z要多? SETTINGS_MAX_FRAME_SIZEQ即2^142=32768Q,否则包头太大Q隐患多多?/p>

标志位: * ACK (0x1)Q表C接收者已l接收到SETTING帧,作ؓ认必须讄此标志位Q此时负载ؓI,否则需要报FRAME_SIZE_ERROR错误

注意事项Q?- 在连接开始阶D必d许发送SETTINGS帧,但不一定要发?- 在连接的生命周期内可以允怓Q一端点发?- 接收者不需要维护参数的状态,只需要记录当前值即?- SETTINGS帧仅作用于当前连接,不针对单个流Q因此流标识Wؓ0x0 - 不完整或不合规范的SETTINGS帧需要抛出PROTOCOL_ERRORcdq接错误 - 负蝲字节Cؓ6个字节的倍数Q?*N (N>=0)

处理程Q?- 发送端发送需要两端都需要携带有遵守的SETTINGS讄帧,不能够带有ACK标志?- 接收端接收到无ACK标志位的SETTINGS帧,必须按照帧内字段出现序一一q行处理Q中间不能够处理其它?- 接收端处理时Q针对不受支持的参数需忽略 - 接收端处理完毕之后,必须响应一个包含有ACK认标志位、无负蝲的SETTINGS?- 发送端接收到确认的SETTINGS帧,表示两端讄已生?- 发送端{待认若超Ӟ报SETTINGS_TIMEOUTcdq接错误

2. HEADER

+-----------------------------------------------+
|                Length (24)                    |
+---------------+---------------+---------------+
|    0x1 (8)    | 00?0 ??0? (8) |
+-+-------------+---------------+-------------------------------+
|R|                Stream Identifier (31)                       |
+=+=============+===============================================+
|Pad Length? (8)|
+-+-------------+-----------------------------------------------+
|E|                 Stream Dependency? (31)                     |
+-+-------------+-----------------------------------------------+
|  Weight? (8)  |
+-+-------------+-----------------------------------------------+
|                   Header Block Fragment (*)                 ...
+---------------------------------------------------------------+
|                           Padding (*)                       ...
+---------------------------------------------------------------+

报头主要载体Q请求头或响应头Q同时呢也用于打开一个流Q在处于打开"open"或者远E半关闭"half closed (remote)"状态都可以发送?/p>

字段列表Q?- Pad LengthQ受制于PADDED标志控制是否昄Q?个比特表C填充的字节数?- EQ一个比特表C流依赖是否专用Q可选项Q只在流优先UPRIORITY被设|时有效 - Stream DependencyQ?1个比特表C流依赖Q只在流优先UPRIORITY被设|时有效 WeightQ?个比特(一个字节)表示无符L自然数流优先U,D围自然是(1~256)Q或UC为权重。只在流优先UPRIORITY被设|时有效 - Header Block FragmentQ报头块分片 - PaddingQ填充的字节Q受制于PADDED标志控制是否昄Q长度由Pad Length字段军_

所需标志位: END_STREAM (0x1): 报头块ؓ最后一个,意味着的l束。后l可紧接着CONTINUATION帧在当前的流中,需要把CONTINUATION帧作为HEADERS帧的一部分对待 END_HEADERS (0x4): 此报头不需分片Q完整的一个。后l不再需要CONTINUATION帧帮忙凑齐。若没有此标志的HEADER帧,后箋帧必L以CONTINUATION帧传递在当前的流中,否则接收者需要响应PROTOCOL_ERRORcd的连接错误?PADDED (0x8): 需要填充的标志 PRIORITY (0x20): 优先U标志位Q控制独立标志位EQ流依赖Q和权重?/p>

注意事项Q?- 其负载ؓ报头块分片,若内容过大,需要借助于CONTINUATION帧l传输。若标识符?x0Q结束段需要返回PROTOCOL_ERRORq接异常。HEADERS帧包含优先信息是ؓ了避免潜在的不同之间优先序的干扰?- 其实一般来Ԍ报文头部不大的情况下Q一个HEADERS可以完成了Q特D情况就是Cookie字段过16KiB大小Q不常见?/p>

3. CONTINUATION

+-----------------------------------------------+
|                Length (24)                    |
+---------------+---------------+---------------+
|  0x9 (8)      |  0x0/0x4  (8) |
+-+-------------+---------------+-------------------------------+
|R|                Stream Identifier (32)                       |
+=+=============================================================+
|                  Header Block Fragment (*)                    |
+---------------------------------------------------------------+

字段列表Q?- Header Block FragmentQ用于协助HEADERS/PUSH_PROMISE{单帧无法包含完整的报头剩余部分数据?/p>

注意事项Q?- 一个HEADERS/PUSH_PROMISE帧后面会跟随零个或多个CONTINUATIONQ只要上一个没有讄END_HEADERS标志位,׃一个完整数据的结束?- 接收端处理此U情况,从开始的HEADERS/PUSH_PROMISE帧到最后一个包含有END_HEADERS标志位l束Q合q的数据才算是一份完整数据拷?- 在HEADERS/PUSH_PROMISEQ没有END_HEADERS标志位)和CONTINUATION帧中_是不能够掺杂其它帧的Q否则需要报PROTOCOL_ERROR错误

标志位: * END_HEADERS(0X4)Q表C报头块的最后一个Q否则后面还会跟随CONTINUATION帧?/p>

4. DATA

一个或多个DATA帧作求、响应内容蝲体,较ؓ完整的结构如下:

+-----------------------------------------------+
|                Length (24)                    |
+---------------+---------------+---------------+
| 0x0 (8)       | 0000 ?00? (8) |
+-+-------------+---------------+-------------------------------+
|R|                Stream Identifier (31)                       |
+=+=============+===============================================+
|Pad Length? (8)|
+---------------+-----------------------------------------------+
|                            Data (*)                         ...
+---------------------------------------------------------------+
|                          Padding? (*)                       ...
+---------------------------------------------------------------+

字段Q?Pad Length: 一个字节表C填充的字节长度。取决于PADDED标志是否被设|? Data: q里是应用数据,真正大小需要减d他字D(比如填充长度和填充内容)长度?* Padding: 填充内容q个0x0字节Q受PADDED标志控制是否昄。接收端处理时可忽略验证填充内容。若验证Q可以对?x0内容填充回应PROTOCOL_ERRORcdq接异常?/p>

标志位: END_STREAM (0x1): 标志此为对应标志流最后一个Q流q入了半关闭/关闭状态?PADDED (0x8): 负蝲需要填充,Padding Length + Data + Paddingl成?/p>

注意事项Q?- 若流标识Wؓ0x0Q接收者需要响应PROTOCOL_ERRORq接错误 - DATA帧只能在处?open" or "half closed (remote)"状态时被发送出去,否则接收端必d应一个STREAM_CLOSED的连接错误。若填充长度不小于负载长度,接收端必d应一个PROTOCOL_ERRORq接错误?/p>

5. PUSH_PROMISE

+-----------------------------------------------+
|                Length (24)                    |
+---------------+---------------+---------------+
|  0x5 (8)      | 0000 ??00 (8) |
+-+-------------+---------------+-------------------------------+
|R|                Stream Identifier (32)                       |
+=+=============================================================+
|Pad Length? (8)|
+-+-------------+-----------------------------------------------+
|R|                Promised Stream ID (31)                      |
+-+-------------------------------------------------------------+
|                  Header Block Fragment (*)                . . .
+---------------------------------------------------------------+
|                           Padding (*)                     . . .
+---------------------------------------------------------------+

服务器端通知对端初始化一个新的推送流准备E后推送数据: - 要求推送流为打开或远端半关闭Qhalf closed (remote)Q状态,否则报PROTOCOL_ERROR错误Q?- 承诺的流不一定要按照其流打开序q行使用Q仅用作E后使用 - 受对端所讄SETTINGS_ENABLE_PUSH标志位决定是否发送,否则作ؓPROTOCOL_ERROR错误对待 - 接收端一旦拒l接收推送,会发送RST_STREAM帧告知对Ҏ送无?/p>

字段列表Q?- Promised Stream IDQ?1个比特表C无W号的自然数Qؓ推送保留的标识符Q后l适用于发送推送数?- Header Block FragmentQ请求头部字D|可看做是服务器端模拟客户端发起一ơ资源请?/p>

标志位: END_HEADERSQ?x4/00000010Q,此包含完整的报头块Q不用后面跟随CONTINUATION帧了 PADDEDQ?x8/00000100Q,填充开养I军_了下面的Pad Length和Padding是否要填充,具体和HEADERS帧内容一_不多?/p>

6. PING

优先UQ类型gؓ0x6Q?个字节表C。发送者测量最往q时_心蟩机制用于空闲连接是否有效?/p>

+-----------------------------------------------+
|                0x8 (24)                       |
+---------------+---------------+---------------+
|  0x6 (8)      | 0000 000? (8) |
+-+-------------+---------------+-------------------------------+
|R|                          0x0 (32)                           |
+=+=============================================================+
|                        Opaque Data (64)                       |
+---------------------------------------------------------------+

字段列表Q?- Opaque DataQ?个字节负载,值随意填写?/p>

标志位: * ACK(0x1)Q一旦设|,表示此PING帧ؓ接收者响应的PING帧,非发送者?/p>

注意事项Q?- PING帧发送方ACK标志位ؓ0x0Q接收方响应的PING帧ACK标志位ؓ0x1。否则直接丢弃。其优先U要高于其它cd帧?- PING帧不和具体流相关联,若流标识Wؓ0x0Q接收方需要响应PROTOCOL_ERRORcdq接错误?- 过负蝲长度Q接收者需要响应FRAME_SIZE_ERRORcdq接错误?/p>

7. PRIORITY

优先UQ类型gؓ0x2Q?个字节表C。表达了发送方Ҏ优先U权重的|在流的Q何状态下都可以发送,包括I闲或关闭的?/p>

+-----------------------------------------------+
|                   0x5 (24)                    |
+---------------+---------------+---------------+
|   0x2 (8)     |    0x0 (8)    |
+-+-------------+---------------+-------------------------------+
|R|                  Stream Identifier (31)                     |
+=+=============================================================+
|E|                  Stream Dependency (31)                     |
+-+-------------+-----------------------------------------------+
| Weight (8)    |
+---------------+

字段列表Q?- EQ流是否独立 - Stream DependencyQ流依赖Qgؓ的标识W,自然也是31个比特表C?- WeightQ权?优先U,一个字节表C然数Q范?~256

注意事项Q?- PRIORITY帧其标识符?x0Q接收方需要响应PROTOCOL_ERRORcd的连接错误?- PRIORITY帧可在流的Q何状态下发送,但限制是不能够在一个包含有报头块连l的帧里面出玎ͼ其发送时刻需要,若流已经l束Q虽然可以发送,但已l没有什么效果?- 过5个字节PRIORITY帧接收方响应FRAME_SIZE_ERRORcd错误?/p>

8. WINDOW_UPDATE

+-----------------------------------------------+
|                0x4 (24)                       |
+---------------+---------------+---------------+
|   0x8 (8)     |    0x0 (8)    |
+-+-------------+---------------+-------------------------------+
|R|                Stream Identifier (31)                       |
+=+=============================================================+
|R|              Window Size Increment (31)                     |
+-+-------------------------------------------------------------+

量控制帧,作用于单个流以及整个q接Q但只能影响两个端点之间传输的DATA数据帧。但需注意Q中介不转发此?/p>

字段列表Q?- Window Size IncrementQ?1个比特位无符可然数Q范围ؓ1-2^31-1Q?,147,483,647Q个字节敎ͼ表明发送者可以发送的最大字节数Q以及接收者可以接收到的最大字节数?/p>

注意事项Q?- 目前控只会影响到DATA数据?- 标识符?Q媄响整个连接,非单个流 - 标识符不ؓI,具体的标识W,只能够影响到具体流 - WINDOW_UPDATE在某个携带有END_STREAM帧的后面被发送(当前处于关闭或q程关闭状态)Q接收端可忽略,但不能作为错误对?- 发送者不能发送一个窗口值大于接收者已持有Q接收端已经拥有一个流控窗口|可用I间大小的WINDOW_UPDATE?- 当流控窗口所讄可用I间已耗尽Ӟ对端发送一个零负蝲带有END_STREAM标志位的DATA数据帧,q是允许的行?- 量控制不会计算帧头所占用?个字节空?- 若窗口值溢出,针对单独,响应RST_STREAMQ错误码FLOW_CONTROL_ERRORQQ针Ҏ个连接的Q响应GOAWAYQ错误码FLOW_CONTROL_ERRORQ - DATA数据帧的接收方在接收到数据之后Q需要计已消耗的控H口可用I间Q同时要把最新可用窗口空间发送给对端 - DATA数据帧发送方接收到WINDOW_UPDATE帧之后,获取最新可用窗口?- 接收方异步更新发送方H口|避免停?失?- 默认情况下流量控制窗口gؓ65535Q除非接收到SETTINGS帧SETTINGS_INITIAL_WINDOW_SIZE参数Q或者WINDOWS_UPDATE帧携带的H口值大,否则不会改变 - SETTINGS_INITIAL_WINDOW_SIZE值的改变会导致窗口可用空间不明晰Q易出问题,发送者必d止受控影响的DATA数据帧的发送直到接收到WINDOW_UPDATE帧获得新的窗口|才会l箋发送。egQ客L在连接徏立的瞬间一口气发送了60KB的数据,但来自服务器SETTINGS讄帧的初始H口gؓ16KBQ客L只能够等到WINDOW_UPDATE帧告知新的窗口|然后l箋发送传送剩下的44KB数据 - SETTINGS帧无法修攚wҎ个连接的量控制H口?- M端点在处理SETTINGS_INITIAL_WINDOW_SIZE值时一旦导致流控窗口D出最大|都需要作Z个FLOW_CONTROL_ERRORcdq接错误对待

9. RST_STREAWM

优先UQ类型gؓ0x3Q?个字节表C。表达了发送方Ҏ优先U权重的|M旉M都可以发送,包括I闲或关闭的?/p>

+-----------------------------------------------+
|                0x4 (24)                       |
+---------------+---------------+---------------+
|  0x3  (8)     |  0x0 (8)      |
+-+-------------+---------------+-------------------------------+
|R|                Stream Identifier (31)                       |
+=+=============================================================+
|                        Error Code (32)                        |
+---------------------------------------------------------------+

字段列表Q?- Error CodeQ错误代码,32位无W号的自然数表示被关闭的错误原因?/p>

注意事项Q?- 接收到RST_STREAM帧,需要关闭对应流Q因此流也要处于关闭状态?- 接收者不能够在此上发送Q何?- 发送端需要做好准备接收接收端接收到RST_STREAM帧之前发送的帧,q个I隙的需要处理?- 若流标识Wؓ0x0Q接收方需要响应PROTOCOL_ERRORcdq接错误?- 当流处于I闲状态idle状态时是不能够发送RST_STREAM帧,否则接收方会报以PROOTOCOL_ERRORcdq接错误?/p>

10. GOAWAY

+-----------------------------------------------+
|                Length (24)                    |
+---------------+---------------+---------------+
|  0x7 (8)      |     0x0 (8)   |
+-+-------------+---------------+-------------------------------+
|R|                Stream Identifier (32)                       |
+=+=============================================================+
|R|                  Last-Stream-ID (31)                        |
+-+-------------------------------------------------------------+
|                      Error Code (32)                          |
+---------------------------------------------------------------+
|                  Additional Debug Data (*)                    |
+---------------------------------------------------------------+

一端通知对端较ؓ优雅的方式停止创建流Q同时还要完成之前已建立的d?/p>

  • 一旦发送,发送者将忽略接收到的标识符大于Last-Stream-IDM?
  • 接收者不能够在当前流上创建新,若创建新则创徏新的q接
  • 可用于服务器的管理行为,比如服务器进入维护阶D,不再准备接收新的q接
  • 字段Last-Stream-ID为发送方取自最后一个正在处理或已经处理的标识W?
  • 后箋创徏的流标识W高于Last-Stream-ID数据帧都不会被处?
  • l端应被鼓励在关闭连接之前发送GOAWAY隐式方式告知Ҏ某些是否已l被处理
  • l端可以选择关闭q接Q针对行Z当的l端不发送GOAWAY?
  • GOAWAY应用于当前连接,非具体流
  • 没有处理M的情况下,Last-Stream-ID值可?Q也是合?
  • (标识W小于或{于已有~号的标识符Q在q接关闭之前没有被完全关闭,需要创建新的连接进行重?
  • 发送端在发送GOAWAY时还有一些流d没有完成Q将保持q接为打开状态直CQ务完?
  • l端可以在自w环境发生改变时发送多个GOAWAY帧,但Last-Stream-ID不允许增?
  • Additional Debug Data没有语义Q仅用于联机试诊断目的。若携带登陆或持久化调试数据Q需要有安全保证避免未经授权讉K?

四。的扩?/h3>

HTTP/2协议的扩展是允许存在的,在于提供额外服务。扩展包括: - 新类型Q需要遵守通用帧格?- 新的讄参数Q用于设|新帧相兛_?- 新的错误代码Q约定可能触发的错?/p>

当定义一个新帧,需要注?1. 规范新的扩展需要经q双方协商后才能使用 1. 在SETTINGS帧添加新的参数项Q可在连接序a时发送给对端Q或者适当Z发?1. 双方协商成功Q可以用新的扩?/p>

已知ALTSVC、BLOCKED属于扩展帧?/p>

1. ALTSVC

服务器提供给客户端当前可用的替代服务Q类gCNAMEQ客L不支持可用选择忽略

+-----------------------------------------------+
|                Length (24)                    |
+---------------+---------------+---------------+
|  0xa (8)      |     0x0 (8)   |
+-+-------------+---------------+-------------------------------+
|R|                Stream Identifier (32)                       |
+=+=============================+===============================+
|         Origin-Len (16)       | Origin? (*)                 ...
+-------------------------------+-------------------------------+
|                   Alt-Svc-Field-Value (*)                   ...
+---------------------------------------------------------------+

字段列表Q?- Origin-Len: 16比特位整敎ͼ说明了Origin字段字节?- Origin: ASCII字符串表C替代服?- Alt-Svc-Field-Value: 包含了Alt-Svc HTTP Header FieldQ长?Length (24) - Origin-Len (16)

需要注意: - 中介讑֤不能转发l客LQ原因就是中介自w替换处理,转发正常的业务数据给客户端就?/p>

具体可参考:https://tools.ietf.org/html/draft-ietf-httpbis-alt-svc-06

2. BLOCKED

一端告诉另一端因为受到流量控制的作用有数据但无法发送?/p>

+-----------------------------------------------+
|                Length (24)                    |
+---------------+---------------+---------------+
|  0xb (8)      |     0x0 (8)   |
+-+-------------+---------------+-------------------------------+
|R|                Stream Identifier/0x0 (32)                   |
+=+=============================================================+
  • Stream Identifier若ؓ0x0Q则表示针对整个q接Q否则针对具体流
  • 在流量控制窗口生效之前不能发送BLOCKED
  • 一旦遇到此w题,说明我们的实现可能有~陷Q无法得到理想的传输速率
  • 只能够在WINDOW_UPDATE帧接收之前或SETTINGS_INITIAL_WINDOW_SIZE参数增加之前发?

五。小l?/h3>

以上记录了HTTP/2帧基本结构,10个文档定义的正式帧,以及额外的两个扩展?/p>

nieyong 2015-03-20 09:24 发表评论
]]>HTTP/2W记之流和多路复?/title><link>http://www.aygfsteel.com/yongboy/archive/2015/03/19/423611.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Thu, 19 Mar 2015 02:15:00 GMT</pubDate><guid>http://www.aygfsteel.com/yongboy/archive/2015/03/19/423611.html</guid><wfw:comment>http://www.aygfsteel.com/yongboy/comments/423611.html</wfw:comment><comments>http://www.aygfsteel.com/yongboy/archive/2015/03/19/423611.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/yongboy/comments/commentRss/423611.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/yongboy/services/trackbacks/423611.html</trackback:ping><description><![CDATA[<div id="wmqeeuq" class="wrap"> <h3 id="-">零。前a</h3> <p>本部分将讲解HTTP/2协议中对的定义和用,其实是在说HTTP/2是若何做到多路复用的?/p> <h3 id="-">一。流和多路复用的关系</h3> <h4 id="1-">1. 的概念</h4> <p>(StreamQ,服务器和客户端在HTTP/2q接内用于交换数据的独立双向序列,逻辑上可看做一个较为完整的交互处理单元Q即表达一ơ完整的资源h-响应数据交换程Q一个业务处理单元,在一个流内进行处理完毕,q个生命周期完l?/p> <p>特点如下Q?/p> <ul> <li>一个HTTP/2q接可同时保持多个打开的流QQ一端点交换? </li><li>可被客L或服务器单独或共享创建和使用 </li><li>可被Q一端关? </li><li>在流内发送和接收数据都要按照序 </li><li>的标识W自然数表示Q?~2^31-1区间Q有创徏的l端分配 </li><li>与之间逻辑上是q行、独立存?</li></ul> <h4 id="2-">2. 多\复用</h4> <p>的概念提出是ؓ了实现多路复用,在单个连接上实现同时q行多个业务单元数据的传输。逻辑囑֦下:</p> <p><img alt="" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/5264ea818301_D4ED/one_http2_connection_thumb_1.png" /></p> <p>实际传输可能是这LQ?/p> <p><img alt="" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/5264ea818301_D4ED/http2_multiplexing_real_thumb.png" /></p> <p>只看到(Frame)Q没有流QStreamQ嘛?/p> <p>需要抽象化一些,好理解了:</p> <ol> <li>每一个可看做是一个学生,可以认为是l(标识符为的属性|Q一个班U(一个连接)内学生被分ؓ若干个小l,每一个小l分配不同的具体d? </li><li>HTTP/1.* 一ơ请?响应Q徏立一个连接,用完关闭Q每一个小lQ务都需要徏立一个班U,多个组d多个班Q?:1比例 </li><li>HTTP/1.1 Pipeling解决方式为,若干个小lQ务排队串行化单线E处理,后面组d{待前面组d完成才能获得执行ZQ一旦有d处理时{,后箋d只能被阻塞,毫无办法Q也是Z常说的线头阻? </li><li>HTTP/2多个组d可同时ƈ行(严格意义上是q发Q在班内执行。一旦某个小lQ务耗时严重Q但不会影响到其它小lQ务正常执? </li><li>针对一个班U资源维护要比多个班U资源维护经多了,q也是多路复用出现的原因 </li></ol> <p>q样单梳理,有些小清晰了?/p> <h4 id="3-">3. 的l成</h4> <p>的概念提出Q就是ؓ了实现多路复用。媄响因素:</p> <ol> <li>的优先U(priorityQ属性徏议终端(客户?服务器端Q需要按照优先D行资源合理分配,优先U高的需要首先处理,优先U低的可以稍微排排队Q这L机制可保证重要数据优先处理? </li><li>的q发敎ͼ或者说同一旉存在的流的个敎ͼ初始环境下不于100? </li><li>量控制阀协调|络带宽资源利用Q由接收端提出发送端遵守其规? </li><li>具有完整的生命周期Q从创徏到最l关闭,l历不同阶段 </li></ol> <p>Ml成如下Q?/p> <p><img alt="" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/5264ea818301_D4ED/http2_stream_thumb.png" /></p> <p>搞清楚了和多\复用之间关系Q下面稍微深入一点,学习的一些细节?/p> <h3 id="-">二。流的属?/h3> <h4 id="1-">1. 状?生命周期</h4> <p><img alt="" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/5264ea818301_D4ED/http2%20stream%20status_thumb.png" /></p> <p>帧的行ؓ以及END_STREAM标志位都会对的状态的产生变化。因为流由各个端独立创徏Q没有协商,消极后果是Q两端无法匹配的的状态)D发送完毕RST_STREAM帧之?#8220;关闭”状态受限,因ؓ帧的传输和接攉要一Ҏ间?/p> <p>帧的状态列表:</p> <ol> <li>idleQ所有流的开始状态?<ul> <li>发?接收HEADERS帧,q入open状? </li><li>PUSH_PROMISE帧只能在已有上发送,D创徏的本地推送流处于"resereved(local)"状? </li><li>在已有流上接收PUSH_PORMISE帧,D本地预留一个流处于"resereved(remote)"状? </li><li>HEADERS/PUSH_PROMISE帧以及后面的零个或多个CONTINUATION帧,只要携带有END_STREAM标志位,状态将q入"half closed"状? </li><li>只能接收HEADERS和PRIORITYQ否则报PROTOCOL_ERRORcdq接错误 </li></ul> </li><li> <p>reservedQؓ推送保留一个流E后使用</p> <ol> <li>reserved (local)Q服务器端发送完PUSH_PROMISE帧本地预留的一个用于推送流所处于的状?<ul> <li>只能发送HEADERS、RST_STREAM、PRIORITY? </li><li>只能接收RST_STREAM、PRIORITY、WINDOW_UPDATE?</li></ul> </li><li> <p>reserved (remote)Q客L接收到PUSH_PROMISE帧,本地预留的一个用于接收推送流所处于的状?/p> <ul> <li>只能发送WINDOW_UPDATE、RST_STREAM、PRIORITY? </li><li>只能接收RST_STREAM、PRIORITY、HEADERS?</li></ul> <p>不满xӞ需要报PROTOCOL_ERRORcdq接错误</p></li></ol> </li><li>openQ用于两端发送Q需要发送数据的对等端需要遵守流量控制的通告?<ul> <li>每一端可以发送包含END_STREAM标志位的帧,D进?half closed"状? </li><li>每一端都可以发送RST_STREAM帧,进?closed"状?</li></ul> </li><li> <p>half closed</p> <ol> <li>half closed (local)Q发送包含有END_STREAM标志位的一端,进入本地半关闭状?<ul> <li>不能发送WINDOW_UPDATEQPRIORITY和RST_STREAM? </li><li>可以接收CQ何类型 </li><li>接收者可以忽略WINDOW_UPDATE帧,后箋可能会马上接收到包含有END_STREAM标志位 </li><li>接收C先PRIORITY帧,可用来变更依赖流的优先序Q有些小复杂? </li><li>一旦接收到包含END_STREAM标志位的帧,进?closed"状?</li></ul> </li><li> <p>half closed (remote)Q接收到包含有END_STREAM标志位的一端,进入远E半关闭状?/p> <ul> <li>Ҏ量控制窗口可不用l护 </li><li>只能接收RST_STREAM、PRIORITY、WINDOW_UPDATE帧,否则报STREAM_CLOSED错? </li><li>l端可以发送Q何类型Q但需要遵守对端的当前的量控制限制 </li><li>一旦发送包含END_STREAM标志位的帧,进?closed"状?</li></ul> <p>一旦接收或发送RST_STREAM帧,将q入"closed"状态?/p></li></ol> </li><li>closedQ流的最l关闭状?<ul> <li>只允许发送PRIORITY帧,对依赖关闭的进行重排序 </li><li>l端接收RST_STREAM帧之后,只能接收PRIORITY帧,否则报STREAM_CLOSED错? </li><li>接收的DATA/HEADERS帧包含有END_STREAM标志位,在一个很短的周期内可以接收WINDOW_UPDATE或RST_STREAM帧;时后需要作为错误对? </li><li>l端必须忽略WINDOW_UPDATE或RST_STREAM? </li><li>l端发送RST_STREAM帧之后,必须忽略M接收到的? </li><li>在RST_STREAM帧被发送之后收到的量受限DATA帧,转向量控制H口q接处理。尽这些可以被忽略,因ؓ他们是在发送端接收到RST_STREAM之前发送的Q但发送端会认些与流量控制窗口不W? </li><li>l端在发送RST_STREAM之后接收PUSH_PROMISE帧,管相关已被重|,但推送也能使流变成“保留”状态。因此,可用RST_STREAM帧关闭一个不惌的承诺流 </li></ul></li></ol> <p>要求如下Q?/p> <ol> <li>针对具体状态中出现没有允许出现的Q需要作为协议错?PROTOCOL_ERROR)cd的连接错误处? </li><li>在流的Q何状态下QPRIORITY帧都可以被发送或接收 </li><li>未知帧可以被忽略 </li></ol> <h4 id="2-">2. 标识符</h4> <ol> <li>31个字节表C无W号的整敎ͼ1~2^31-1 </li><li>客户端创建的以奇数表示Q服务器端创建流以偶数表C? </li><li>0x0用来表示q接控制信息,不能够创建新? </li><li>通过http/1.1 101 协议切换升切换到HTTP/2Q?x1所指代处?half closed(local)"Q不能用于创建新? </li><li>新徏的标识W要大于已有和预留的流的标识符 </li><li>新徏第一ơ被使用Ӟ低于此标识符的ƈ且处于空?idle"状态的都会被关闭 </li><li>已用的标识符不能被再ơ? </li><li>l端的流标识W若被耗尽的情况下 <ul> <li>若是客户端,需要关闭连接,创徏新的q接创徏新流 </li><li>若是服务器端Q需要发送一个GOAWAY帧通知客户端,其打开一个新q接 </li></ul></li></ol> <h4 id="3-">3. 的q发数量</h4> <ol> <li>每一端都可以发送包含有SETTINGS_MAX_CONCURRENT_STREAMS参数的SETTINGS帧限制对{端的最大ƈ发量 </li><li>对等端接收之后遵守终端最大ƈ发量限制U定 </li><li>状态ؓ"open"?half closed"的流需要计入限制L </li><li>保留?reserved"不入限制L? </li><li>l端接收到HEADERS帧导致创建的L过限制Q需要响应PROTOCOL_ERROR或REFUSED_STREAM错误Q具体哪一U错误,需要根据终端是否可以检得到允许自动重复重? </li><li>l端想降低SETTINGS_MAX_CONCURRENT_STREAMS讄的活动流的上限,若低于当前已l打开的数|可以选择光比溢出的流或者允许流l箋存在直到完成 </li></ol> <h4 id="4-">4. 的优先U?/h4> <p>的优先U在于允许终端向对端表达所期待的给予具体流更多资源支持的意见的表达Q不能保证对端一定会遵守Q非强制性需求徏议;默认?6。在资源有限Ӟ可以保证基本数据的传输?/p> <p>优先U改变:</p> <ol> <li>l端可在新徏的流所传递HEADERS帧中包含优先Upriority属? </li><li>可单独通过PRIORITY帧专门设|流的优先属?</li></ol> <h4 id="5-">5. 依?/h4> <ol> <li>与之间存在依赖、被依赖关系。所有流默认依赖?x0Q推送流依赖于传输PUSH_PROMISE的关联流? </li><li>依赖权重?~256区间Q对于依赖同一父的子节点Q应该根据权重比列进行分配资源? </li><li>对于依赖同一个父U流的子节点被指定相x重|以及可用资源的分配比重。子节点之间序不固定?pre><code> A A / \ ==> /|\ B <span id="wmqeeuq" class="hljs-keyword">C</span> B <span id="wmqeeuq" class="hljs-keyword">D</span> <span id="wmqeeuq" class="hljs-keyword">C</span> </code></pre> </li><li>一旦设|独家专属标志(exclusive flagQ将为现有依赖插入一个水q的依赖关系Q其父񔋹只能被插入的新所依赖。比如流D讄专属标志q依赖于AQ?pre><code> A A | / \ ==> <span id="wmqeeuq" class="hljs-keyword">D</span> B <span id="wmqeeuq" class="hljs-keyword">C</span> / \ B <span id="wmqeeuq" class="hljs-keyword">C</span> </code></pre> </li><li>的依赖树Ş模型Q底层的只能等C层流被关闭或无法正常q{/失效Ӟ才会被分配到资源 </li><li>无法依赖自w,否则为PROTOCOL_ERROR错? </li><li>在流依赖树Ş模型中,父节点优先Q以及专属依赖流的加入等Q都会导致已有优先重排?pre><code> ? ? ? ? | / \ | | A <span id="wmqeeuq" class="hljs-keyword">D</span> A <span id="wmqeeuq" class="hljs-keyword">D</span> <span id="wmqeeuq" class="hljs-keyword">D</span> / \ / / \ / \ | B <span id="wmqeeuq" class="hljs-keyword">C</span> ==> F B <span id="wmqeeuq" class="hljs-keyword">C</span> ==> F A OR A / \ | / \ /|\ <span id="wmqeeuq" class="hljs-keyword">D</span> <span id="wmqeeuq" class="hljs-keyword">E</span> <span id="wmqeeuq" class="hljs-keyword">E</span> B <span id="wmqeeuq" class="hljs-keyword">C</span> B <span id="wmqeeuq" class="hljs-keyword">C</span> F | | | F <span id="wmqeeuq" class="hljs-keyword">E</span> <span id="wmqeeuq" class="hljs-keyword">E</span> (intermediate) (non-exclusive) (exclusive) </code></pre></li></ol> <h4 id="6-">6. 优先状态管?/h4> <ol> <li>的依赖树Ş模型QQ一节点被移除,都需要重Z先序Q重新分配资? </li><li>l端在流关闭一D|间内保留优先U信息,减少潜在的指zN? </li><li>处于"idle"状态流可被指派默认优先U?6Q这时可以变成其它流的父节点Q可以指z新的优先? </li><li>l端持有的流优先U信息不受SETTINGS_MAX_CONCURRENT_STREAMS限制Q但可能会造成l端状态维护负担,其数量可以被限制不多于SETTINGS_MAX_CONCURRENT_STREAMS所定义数量 </li><li>优先U状态信息的l持在负载较高时可以被丢弃,以减资源占用? </li><li>l端若有能力保留_状态,在接收到PRIORITY帧目的修改已被关闭流的优先Ӟ可以为其子节炚wZ先序 </li></ol> <h4 id="7-">7. 量控制</h4> <p>多\复用会引入资源竞争,量控制可以保证之间不会严重媄响到彼此。流量控刉过使用WINDOW_UPDATE帧实玎ͼ可作用于单个以及整个的q接。一些原则如下:</p> <ol> <li>逐蟩Q具有方向? </li><li>不能够被止 </li><li>初始H口gؓ65535字节Q针对单个流Q以及整个连接都有效 </li><li>ZWINDOW_UPDATE帧传输实玎ͼ接收端通告对端准备在流/q接上接收的字节? </li><li>接收端完全控制权限,接受端可通告针对?q接的窗口|发送者需要遵? </li><li>目前只有DATA帧可被流量控Ӟ仅针对其有效负蝲计算Q超出窗口|其负载可以ؓI?</li></ol> <p>需要注意事:</p> <ol> <li>量控制是ؓ解决U头d问题Q同时在资源U束情况下保护一些操作顺利进行,针对单个q接Q某个流可能被阻塞或处理~慢Q但同时不会影响到其它流上正在传输的数据 </li><li>虽然量控制可以用来限制一个对{端消耗的内存Q但若在不知道网l带宽gq乘U的情况下可能未必能够充分利用好|络资源 </li><li>量控制机制很复杂,需要考虑大量的细节,实现很困?</li></ol> <h3 id="-">三。小l?/h3> <p>HTTP/2规范中所定义的流概念、属性很复杂Q在h量很大以及应Ҏv量ƈ发的情况下,整个q接的流量控?单个的量控制+的状?优先属?优先U的状?依赖树形模型等一pd新特性,可能会造成Q?/p> <ol> <li>服务器端/客户端单个连接内存占用过高,l护一个长q接的成本比以往多了若干? </li><li>量控制是一个复杂功能,实现不好会导致一端流量窗口值已被耗尽Q需要等待客L发送新的流控窗口|若有热数据进行发送,需要等待成本,无Ş中增加了额外的交互步? </li><li>依赖和优先U重排序{,无Ş中增加了E序的复杂度Q处理不好触发潜在BUG </li><li>Z性能和内存考虑Q很多知名应用不见得有动力实现全部特性,的一些高U特性毕竟有些过于理惛_Q诸如当前实现列表:<a >https://github.com/http2/http2-spec/wiki/Implementations</a>Q可以看Z? </li><li>实际非浏览器环境Q诸如HTTP API{,实际上仅需要部分关键特性,q属于情理之中的选择 </li><li>凡是状态皆需要维护,无论横向q是U向的扩展都需要倍加注意Q无状态才是最有利于扩?</li></ol></div><img src ="http://www.aygfsteel.com/yongboy/aggbug/423611.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/yongboy/" target="_blank">nieyong</a> 2015-03-19 10:15 <a href="http://www.aygfsteel.com/yongboy/archive/2015/03/19/423611.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HTTP/2W记之连接徏?/title><link>http://www.aygfsteel.com/yongboy/archive/2015/03/18/423570.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Wed, 18 Mar 2015 05:54:00 GMT</pubDate><guid>http://www.aygfsteel.com/yongboy/archive/2015/03/18/423570.html</guid><wfw:comment>http://www.aygfsteel.com/yongboy/comments/423570.html</wfw:comment><comments>http://www.aygfsteel.com/yongboy/archive/2015/03/18/423570.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/yongboy/comments/commentRss/423570.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/yongboy/services/trackbacks/423570.html</trackback:ping><description><![CDATA[<div id="wmqeeuq" class="wrap"> <h3 id="-">前言</h3> <p>HTTP/2协议在TCPq接之初q行协商通信Q只有协商成功,才会涉及到后l的h-响应{具体的业务型数据交换?/p> <h3 id="http-">HTTP版本标识W?/h3> <ul> <li>h2Q基于TLS之上构徏的HTTP/2Q作为ALPN的标识符Q两个字节表C,0x68, 0x32Q即https</li> <li>h2cQ直接在TCP之上构徏的HTTP/2Q缺乏安全保证,即http</li> <li>在HTTP/2 RFC文档出现之前Q以上版本字D需要添加上草案版本PcM于h2-11,h2c-17</li> </ul> <h4 id="http-2-">HTTP/2 hq程</h4> <p>针对直接建立在标准TCP之上HTTP2Q在未知服务器是否提供HTTP/2支持之前Q可以依赖现有HTTP/1.1q行试探?/p> <h4 id="http-">HTTP版本的请求内?/h4> <ol> <li>客户端发赯求,只有h报头Q?pre><code>GET <span id="wmqeeuq" class="hljs-regexp">/ HTTP/</span><span id="wmqeeuq" class="hljs-number">1.</span> <span id="wmqeeuq" class="hljs-number">1</span> <span id="wmqeeuq" class="hljs-string">Host:</span> server. example. com <span id="wmqeeuq" class="hljs-string">Connection:</span> Upgrade, HTTP2-Settings <span id="wmqeeuq" class="hljs-string">Upgrade:</span> h2c HTTP2-<span id="wmqeeuq" class="hljs-string">Settings:</span> <base64url encoding of HTTP/<span id="wmqeeuq" class="hljs-number">2</span> SETTINGS payload> </code></pre></li> <li>服务器若不支持HTTP/2Q直接按照HTTP/1.1响应卛_<pre><code>HTTP/<span id="wmqeeuq" class="hljs-number">1.</span> <span id="wmqeeuq" class="hljs-number">1</span> <span id="wmqeeuq" class="hljs-number">200</span> OK Content-<span id="wmqeeuq" class="hljs-string">Length:</span> <span id="wmqeeuq" class="hljs-number">243</span> Content-<span id="wmqeeuq" class="hljs-string">Type:</span> text/html . . . </code></pre></li> <li><p>服务器支持HTTP/2Q通知客户端一起切换到HTTP/2协议下吧</p> <pre><code><span id="wmqeeuq" class="hljs-status">HTTP/1. 1 <span id="wmqeeuq" class="hljs-number">101</span> Switching Protocols</span> <span id="wmqeeuq" class="hljs-attribute">Connection</span>: <span id="wmqeeuq" class="hljs-string">Upgrade</span> <span id="wmqeeuq" class="hljs-attribute">Upgrade</span>: <span id="wmqeeuq" class="hljs-string">h2c</span> <span id="wmqeeuq" class="erlang">[ <span id="wmqeeuq" class="hljs-variable">HTTP</span>/<span id="wmqeeuq" class="hljs-number">2</span> connection . . .</span> </code></pre></li> <li>101响应I之后Q服务器必须发送的W一个为SETTINGS帧(其负载可能ؓI)作ؓq接序言</li> <li>客户端接收到101响应后,也必d送一个序a作ؓ响应Q其逻辑l构Q?pre><code>PRI * HTTP/2.0<span id="wmqeeuq" class="hljs-command">\r</span><span id="wmqeeuq" class="hljs-command">\n</span><span id="wmqeeuq" class="hljs-command">\r</span><span id="wmqeeuq" class="hljs-command">\nSM</span><span id="wmqeeuq" class="hljs-command">\r</span><span id="wmqeeuq" class="hljs-command">\n</span><span id="wmqeeuq" class="hljs-command">\r</span><span id="wmqeeuq" class="hljs-command">\n</span> // U字W串表示Q翻译成字节Cؓ24个字? SETTINGS? // 其负载可能ؓI? </code></pre>服务器端和客L所发送的q接序言有所不同?/li> <li>客户端可以马上发送请求或其它q去Q不用等待来自服务器端的SETTINGS?/li> <li>M端接收到SETTINGS帧之后,都需要返回一个包含确认标志位SETTIGN作ؓ认</li> <li>其它帧的正常传输</li> </ol> <h4 id="http-2-">HTTP/2的直接连?/h4> <p>客户端预先知道服务器提供HTTP/2支持Q可以免?01协议切换的流E开销? 具体程Q?/p> <ol> <li>客户端必首先发送一个连接序aQ其逻辑l构Q?pre><code>PRI * HTTP/2.0<span id="wmqeeuq" class="hljs-command">\r</span><span id="wmqeeuq" class="hljs-command">\n</span><span id="wmqeeuq" class="hljs-command">\r</span><span id="wmqeeuq" class="hljs-command">\nSM</span><span id="wmqeeuq" class="hljs-command">\r</span><span id="wmqeeuq" class="hljs-command">\n</span><span id="wmqeeuq" class="hljs-command">\r</span><span id="wmqeeuq" class="hljs-command">\n</span> // U字W串表示Q翻译成字节Cؓ24个字? SETTINGS? // 其负载可能ؓI? </code></pre></li> <li>发送完毕序a之后Q客L可以不用{待来自服务器端响应Q马上发送HTTP/2其它?/li> <li>服务器端接收到客L的连接序a之后Q需要发送一个SETTINGS帧作接序a</li> <li>M端接收到SETTINGS帧之后,都需要返回一个包含确认标志位SETTIGN作ؓ认</li> <li>其它帧的正常传输</li> </ol> <h4 id="https-">HTTPS版本建立q接</h4> <p>HTTP/2安全版本在TLS上构建,协商采用的ALPN扩展协议Q采?#8220;h2”作ؓ协议标识W(http版本则是“h2c”Q。一定程度上可认Z存在试探是否支持或直接连接的烦恼Q因个过E直接在TLS层协商而成?/p> <p>程如下Q?/p> <ol> <li>客户端和服务器端TLS层协?/li> <li>客户端发送连接序aQ同上表C,PRI + SETTINGSQ?/li> <li>接收到客Lq接序言之后Q服务器端发送连接序a</li> <li>双方各自认SETTINGS?/li> <li>其它帧的正常传输</li> </ol> <h4 id="https-http-upgrade-">HTTPS和HTTP Upgrade方式协商</h4> <p>HTTPS协商是强Ӟ装在TLS之上ALPN扩展实现QHTTP只有非直接连接方式才会存在通过101 协议切换方式q行升?/p> <p>q里有一张图形象说明其流E?/p> <p><img src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/5264ea818301_D4ED/image_14.png" alt="" /></p> <h4 id="-">l一的连接过E?/h4> <p>q里不论是HTTPq是HTTPSQ在两端成功协商之后Q或HTTP的直接连接)Q其q接q程都是一L</p> <p><img src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/5264ea818301_D4ED/image_thumb_6.png" alt="" /></p> <h3 id="-">注意事项</h3> <ol> <li>客户端发LHTTP/1.1hQ其标识符?Q默认优先Q半关闭“half closed”状态,一旦完成HTTP/2的连接,被应用于响?/li> <li>文档提到的客L可以通过HTTP Alternative ServicesQ简UCؓ[ALT-SVC]Q类gCNAME机制Q获得通知服务器是否支持HTTP/2Q但目前看来仅仅是草案徏议而已</li> <li>q接序言用于最后两端协商确认双方要使用HTTP/2协议Q徏立初始化的HTTP/2q接环境</li> <li>客户端若知服务器支持HTTP/2Q可免去通过HTTP/1.1 101协议切换方式q行升Q在建立q接后即可发送序aQ否则只能在接收到服务器?01响应后发送序a</li> <li>建立在TLS上的HTTP/2通过ALPN扩展协商机制取代101协议切换</li> <li>q接序言所包含的SETTINGS帧其负蝲可以为空</li> <li>针对一个TCPq接Q服务器W一个要发送的帧必LSETTINGS?/li> <li>Z避免不必要gq,客户端可以在发送完毕序a之后发送数据Q不用等待来自服务器端的序言SETTINGS?/li> <li>客户端接收到服务器端作ؓ序言的SETTINGS帧,需要遵守其讑֮</li> <li>在一些环境下需要提供一个顺序机Ӟ允许服务器在客户端发送业务之前发送SETTINGSQ这需要客L配合</li> <li>客户端和服务器端M一Ҏ收到无效q接序言需要抛出PROTOCOL_ERRORcdq接错误Q若收到GOAWAY帧,可忽?/li> </ol> <h3 id="-">结</h3> <p>HTTP/2q接的徏立协商机制比HTTP/1.1E微复杂了一些?/p> <p>Ҏ明文版的HTTP/1.1和HTTP/2完成一ơ请?响应Q?/p> <ol> <li>HTTP/1.1在徏立徏立之后,只需要发送请求报文数?/li> <li>HTTP/2客户端需要在q接建立之初马上发送一个连接序aq去Q然后才是正常请?/li> <li>两端Q客L+服务器端Q的两次完整的连接序a+认的交互流E,多了两次往q过E?/li> </ol> <p>在弱|络环境下,会不会加重网l负载,只能拭目一看了?/p> <h3 id="-">引用</h3> <ol> <li>《Implementing HTTP/2 client in 60 minutes?/li> </ol> </div><img src ="http://www.aygfsteel.com/yongboy/aggbug/423570.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/yongboy/" target="_blank">nieyong</a> 2015-03-18 13:54 <a href="http://www.aygfsteel.com/yongboy/archive/2015/03/18/423570.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HTTP/2W记之开?/title><link>http://www.aygfsteel.com/yongboy/archive/2015/03/17/423531.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Tue, 17 Mar 2015 06:50:00 GMT</pubDate><guid>http://www.aygfsteel.com/yongboy/archive/2015/03/17/423531.html</guid><wfw:comment>http://www.aygfsteel.com/yongboy/comments/423531.html</wfw:comment><comments>http://www.aygfsteel.com/yongboy/archive/2015/03/17/423531.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.aygfsteel.com/yongboy/comments/commentRss/423531.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/yongboy/services/trackbacks/423531.html</trackback:ping><description><![CDATA[<div class="wmqeeuq" id="out"> <h3>前言</h3> <p>本系列基于HTTP/2W?7个草案文档,地址是Q?a href="https://tools.ietf.org/html/draft-ietf-httpbis-http2-17?>https://tools.ietf.org/html/draft-ietf-httpbis-http2-17?/a></p> <p>HTTP/2规范已经通过发布批准Q下面等待分配具体的RFCLQ不会有所较大的变动了?/p> <p>本笔C是直接翻译,记录成笔记方便以后学习?/p> <h3>HTTP/1.1的问?/h3> <p>一张图可以很较为全面的概括了HTTP/1.*存在~陷Q?/p> <p><img src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/5264ea818301_D4ED/image_thumb_1.png" border="0" height="286" width="616" alt="" /></p> <p>前端一般采用: - CSS SpritingQ小囑֐q成大图QCSSq行分割成小图显C?- InliningQ用DataURL方式内嵌Base64~码格式囄 - JS ConcatenationQ多个JS文g合ƈ成一个,~陷是一旦有文g修改Q需要重新合q?- ShardingQ将资源/服务部v到多个机器上Q均?分nh压力</p> <p>HTTP/1.*没有充分利用TCPҎ,再加上同一个站Ҏ开多个q接{,D|络资源利用率不高?/p> <h3>HTTP/2改进?/h3> <p>与HTTP/1相比Q主要区别包括:</p> <ol> <li>HTTP/2采用二进制格式而非文本格式 <ul> <li>高效紧凑传输解析 </li><li>更少错误們֐Q没有了所谓的I白行、大写、换行符、空q接{?</li></ul> </li><li>HTTP/2是完全多路复用的Q而非有序q塞的 <ul> <li>HTTP/1.1默认情况下单个请求单个连? </li><li>HTTP/1.1水U化pipelining方式D较大/较慢的响应阻塞后lQ? </li><li>HTTP/1.1无法解决U头d的问? </li><li>多\复用可以有效避免U头dQ多个请?响应同一个连接内q行处理 </li></ul> </li><li>只需一个连接即可实现ƈ?<ul> <li>HTTP/1.*h处理模型D同一个站点资源客L需要打开?-8个连接请? </li><li>HTTP/1.*多个q接会占用过多网路资源,DTCP堵塞和数据重? </li><li>HTTP/2单个q接内多个流Q请?响应Q之间ƈ行处理,减少|\资源占用Q可避免了TCP频繁的打开、关?</li></ul> </li><li>使用报头压羃QHTTP/2降低了开销 <ul> <li>传统览器网路报头一般在80-1400字节大小 </li><li>压羃头部可让报头更紧凑,更快速传输,有利于移动网l环境等 </li><li>压羃法使用HPACKQ更为高效、安?</li></ul> </li><li>HTTP/2让服务器可以响应主?#8220;推?#8221;到客L <ul> <li>传统方式Q客LhQ服务器响应Q客L逐一解析需要后l请求的囄、样式等资源Q再ơ一一发送资源请? </li><li>HTTP/2服务器根据客LhQ计出响应内容所包含的资源,在客L发vh之前提前发送给客户? </li><li>节省客户端主动发赯求的旉的往q时?</li></ul></li></ol> <p>q里有一张图Q可以M上了解HTTP/2Q?/p> <p><img src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/5264ea818301_D4ED/image_thumb.png" border="0" height="286" width="616" alt="" /></p> <h4>HTTP/2的解?/h4> <p>保留/兼容HTTP/1.1的所有语义,但传输语法(或者说传输方式Q改变,目的在于更充分利用TCP更高效传输,多\复用是实现途径Q低延迟是改q方向?/p> <h3>W记提纲</h3> <p>以上为简单M介绍了HTTP/2协议Q要x入其Ҏ,需要阅d规范。下面ؓ围绕HTTP/2规范的各个方面,列出提纲Q便于后面一一填充?/p> <ol> <li><a href="http://www.aygfsteel.com/yongboy/archive/2015/03/18/423570.html">HTTP/2的连接徏?/a> </li><li><a href="http://www.aygfsteel.com/yongboy/archive/2015/03/19/423611.html">HTTP/2的多路复用和的属?/a> </li><li><a href="http://www.aygfsteel.com/yongboy/archive/2015/03/20/423655.html">HTTP/2的定义</a> </li><li><a href="http://www.aygfsteel.com/yongboy/archive/2015/03/23/423751.html">HTTP/2的消息交?/a> </li><li><a href="http://www.aygfsteel.com/yongboy/archive/2015/03/24/423791.html">HTTP/2的错误处理和安全事项</a> </li></ol> <h3>名词解释</h3> <p>以下名词会在当前或以后笔C出现Q脓出来方便理解?/p> <ol> <li>中介QintermediationQ,指代包含代理、企业防火墙、反向代理和CDN{互联网讑֤ </li><li>ALPNQApplication Layer Protocol Negotiation </li><li>报头Q报文头部,h报文头部Q或响应报文头部 </li></ol> <h3>结</h3> <p>HTTP/2相比HTTP/1.1Q可以做到更有效的充分利用TCPq接Q避免了TCPq接的重复的创徏Q三ơ握手)、销毁(四次挥手Q的q程?/p> <h3>引用</h3> <ol> <li>《HTTP/2 WebRTC all the things !? </li><li>《Implementing HTTP/2 client in 60 minutes?</li></ol></div><img src ="http://www.aygfsteel.com/yongboy/aggbug/423531.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/yongboy/" target="_blank">nieyong</a> 2015-03-17 14:50 <a href="http://www.aygfsteel.com/yongboy/archive/2015/03/17/423531.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <a href="http://www.aygfsteel.com/" title="狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频">狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频</a> </div> </footer> վ֩ģ壺 <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ľ˹</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank">̨</a>| <a href="http://" target="_blank">Զ</a>| <a href="http://" target="_blank">ƽ̶</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">̺</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ˮ</a>| <a href="http://" target="_blank">˳</a>| <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ƽ</a>| <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank">Զ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ʯ</a>| <a href="http://" target="_blank">ˮ</a>| <a href="http://" target="_blank">Դ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">׷</a>| <a href="http://" target="_blank">ױ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>