您的位置:奥门新浦京网址 > Wed前段 > 让拖放变的流行起来,你所不知道的

让拖放变的流行起来,你所不知道的

发布时间:2019-10-20 03:41编辑:Wed前段浏览(110)

    谈谈 HTTP/2 的协议协商机制

    2016/04/16 · 基础技术 · HTTP/2

    本文作者: 伯乐在线 - JerryQu 。未经作者许可,禁止转载!
    欢迎加入伯乐在线 专栏作者。

    文章目录

    • HTTP Upgrade
    • ALPN 扩展
    • 小结

    在过去的几个月里,我写了很多有关 HTTP/2 的文章,也做过好几场相关分享。我在向大家介绍 HTTP/2 的过程中,有一些问题经常会被问到。例如要部署 HTTP/2 一定要先升级到 HTTPS 么?升级到 HTTP/2 之后,不支持 HTTP/2 的浏览器还能正常访问么?本文重点介绍 HTTP/2 的协商机制,明白了服务端和客户端如何协商出最终使用的 HTTP 协议版本,这两个问题就迎刃而解了。

    HTML5 — 让拖放变的流行起来

    2015/12/29 · HTML5 · 4 评论 · 拖放

    原文出处: 韩子迟   

    先上 Demo,尽量用 chrome,代码可参考 Github。

    在 HTML5 出现之前,页面元素的拖放需要监听 mousedown、mouseover 以及 mouseup 等一系列事件,然后改变元素的相对位置来实现这一效果。HTML DnD(Drag-and-Drop)API 的出现,使得拖放变的简单。但是由于 DnD 尚处在草案阶段,各浏览器对其规范并未统一,有些事件在不同浏览器中会出现不同效果。

    要使用 DnD,需要明确两件事情,一是需要拖动的元素,二是可放置拖动元素的位置。拖放无非是将元素从一个位置拖到另一个位置。

    你所不知道的 HSTS

    2015/10/24 · HTML5 · HSTS

    原文出处: 李靖(@Barret李靖)   

    很多人听说过也看到过 301、302,但是几乎从来没有看到过 303 和 307 的状态码。今天在淘宝首页看到了 307 状态码,于是摸索了一把。

    HTTP Upgrade

    为了更方便地部署新协议,HTTP/1.1 引入了 Upgrade 机制,它使得客户端和服务端之间可以借助已有的 HTTP 语法升级到其它协议。这个机制在 RFC7230 的「6.7 Upgrade」这一节中有详细描述。

    要发起 HTTP/1.1 协议升级,客户端必须在请求头部中指定这两个字段:

    Connection: Upgrade Upgrade: protocol-name[/protocol-version]

    1
    2
    Connection: Upgrade
    Upgrade: protocol-name[/protocol-version]

    客户端通过 Upgrade 头部字段列出所希望升级到的协议和版本,多个协议之间用 ,(0x2C, 0x20)隔开。除了这两个字段之外,一般每种新协议还会要求客户端发送额外的新字段。

    如果服务端不同意升级或者不支持 Upgrade 所列出的协议,直接忽略即可(当成 HTTP/1.1 请求,以 HTTP/1.1 响应);如果服务端统一升级,那么需要这样响应:

    HTTP/1.1 101 Switching Protocols Connection: upgrade Upgrade: protocol-name[/protocol-version] [... data defined by new protocol ...]

    1
    2
    3
    4
    5
    HTTP/1.1 101 Switching Protocols
    Connection: upgrade
    Upgrade: protocol-name[/protocol-version]
     
    [... data defined by new protocol ...]

    可以看到,HTTP Upgrade 响应的状态码是 101,并且响应正文可以使用新协议定义的数据格式。

    如果大家之前使用过 WebSocket,应该已经对 HTTP Upgrade 机制有所了解。下面是建立 WebSocket 连接的 HTTP 请求:

    GET ws://example.com/ HTTP/1.1 Connection: Upgrade Upgrade: websocket Origin: Sec-WebSocket-Version: 13 Sec-WebSocket-Key: d4egt7snxxxxxx2WcaMQlA== Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

    1
    2
    3
    4
    5
    6
    7
    GET ws://example.com/ HTTP/1.1
    Connection: Upgrade
    Upgrade: websocket
    Origin: http://example.com
    Sec-WebSocket-Version: 13
    Sec-WebSocket-Key: d4egt7snxxxxxx2WcaMQlA==
    Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

    这是服务端同意升级的 HTTP 响应:

    HTTP/1.1 101 Switching Protocols Connection: Upgrade Upgrade: websocket Sec-WebSocket-Accept: gczJQPmQ4Ixxxxxx6pZO8U7UbZs=

    1
    2
    3
    4
    HTTP/1.1 101 Switching Protocols
    Connection: Upgrade
    Upgrade: websocket
    Sec-WebSocket-Accept: gczJQPmQ4Ixxxxxx6pZO8U7UbZs=

    在这之后,客户端和服务端之间就可以使用 WebSocket 协议进行双向数据通讯,跟 HTTP/1.1 没关系了。可以看到,WebSocket 连接的建立就是典型的 HTTP Upgrade 机制。

    显然,这个机制也可以用做 HTTP/1.1 到 HTTP/2 的协议升级。例如:

    GET / HTTP/1.1 Host: example.com Connection: Upgrade, HTTP2-Settings Upgrade: h2c HTTP2-Settings:

    1
    2
    3
    4
    5
    GET / HTTP/1.1
    Host: example.com
    Connection: Upgrade, HTTP2-Settings
    Upgrade: h2c
    HTTP2-Settings:

    在 HTTP Upgrade 机制中,HTTP/2 的协议名称是 h2c,代表 HTTP/2 ClearText。如果服务端不支持 HTTP/2,它会忽略 Upgrade 字段,直接返回 HTTP/1.1 响应,例如:

    HTTP/1.1 200 OK Content-Length: 243 Content-Type: text/html ...

    1
    2
    3
    4
    5
    HTTP/1.1 200 OK
    Content-Length: 243
    Content-Type: text/html
     
    ...

    如果服务端支持 HTTP/2,那就可以回应 101 状态码及对应头部,并且在响应正文中可以直接使用 HTTP/2 二进制帧:

    HTTP/1.1 101 Switching Protocols Connection: Upgrade Upgrade: h2c [ HTTP/2 connection ... ]

    1
    2
    3
    4
    5
    HTTP/1.1 101 Switching Protocols
    Connection: Upgrade
    Upgrade: h2c
     
    [ HTTP/2 connection ... ]

    以下是通过 HTTP Upgrade 机制将 HTTP/1.1 升级到 HTTP/2 的 Wireshark 抓包(两张图可以对照来看):

    图片 1

    图片 2

    根据 HTTP/2 协议中的描述,额外补充几点:

    • 41 号包中,客户端发起的协议升级请求中,必须通过 HTTP2-Settings 指定一个经过 Base64 编码过的 HTTP/2 SETTINGS 帧;
    • 45 号包中,服务端同意协议升级,响应正文中必须包含 HTTP/2 SETTING 帧(二进制格式,不需要 Base64 编码);
    • 62 号包中,客户端可以开始发送各种 HTTP/2 帧,但第一个帧必须是 Magic 帧(内容固定为 PRI * HTTP/2.0rnrnSMrnrn),做为协议升级的最终确认;

    HTTP Upgrade 机制本身没什么问题,但很容易受网络中间环节影响。例如不能正确处理 Upgrade 头部的代理节点,很可能造成最终升级失败。之前我们统计过 WebSocket 的连通情况,发现大量明明支持 WebSocket 的浏览器却无法升级,只能使用降级方案。

    Drag


    首先我们需要指定要拖动的元素,设置方式很简单,给该 DOM 元素设置 draggable 属性,属性值设置为 true。比如这样:

    <code> <img src="images/0.jpg" draggable="true" id="img0"/> </code>

    1
    2
    3
    <code>
      <img src="images/0.jpg" draggable="true" id="img0"/>
    </code>

    事实上,以上代码多此一举了,页面中的图片(img)、链接(带 href 的 a 标签)以及文本默认即为可拖动。为了统一,最好还是都加上该 draggable 属性为好。

    draggable 属性还有两个值,分别是 falseauto,顾名思义,false 即设置为不可拖动,auto 即为浏览器默认值。

    当我们左键点击(按下)可拖动的 DOM 元素,轻轻移动,即触发 ondragstart 事件,该事件只会触发一次。通常我们会在 ondragstart 事件中记录正在被拖动的元素信息(ondrop 的时候好对其进行处理)。比如 demo 中记录了正在被拖动的元素 id:

    for (var i = lis.length; i--; ) { lis[i].ondragstart = function(e) { e.dataTransfer.setData('id', e.target.id); }; }

    1
    2
    3
    4
    5
    for (var i = lis.length; i--; ) {
      lis[i].ondragstart = function(e) {
        e.dataTransfer.setData('id', e.target.id);
      };
    }

    ondragstart 事件触发后,直到拖放事件结束,会一直触发 ondrag 事件。

    中间人劫持

    起因是这样,https 使用的是 443 端口进行数据传输,而浏览器的默认端口是

    1. 劫持者首先劫持用户的 80 端口,当用户向目标页发起请求时,劫持者模拟正常的 https 请求向源服务器获取数据,然后通过 80 端口返回给用户,大概可以看下下面两张图:

    图片 3

    用户一般不会在地址栏输入   ,而是习惯性输入 taobao.com  ,此时浏览器走的是 http,请求到达服务器之后,服务器告诉浏览器 302 跳转

    Location:

    1
    Location: https://www.taobao.com

    然后浏览器重新请求,通过 HTTPS 方式,443 端口通讯。而正因为用户不是直接输入 https:// 链接,劫持者利用这一点:

    图片 4

    只要能够劫持你的网络,比如路由劫持、DNS劫持,就可以作为中间人注入代码、替换广告。。。(上了 https 也拗不过电信,真是日了够了)

    这种劫持出现在两种情况下:

    • 用户没有通过准确的方式访问页面,除非输入 https:// ,否则浏览器默认以 http 方式访问
    • HTTPS 页面的链接中包含 http,这个 http 页面可能被劫持

    ALPN 扩展

    HTTP/2 协议本身并没有要求它必须基于 HTTPS(TLS)部署,但是出于以下三个原因,实际使用中,HTTP/2 和 HTTPS 几乎都是捆绑在一起:

    • HTTP 数据明文传输,数据很容易被中间节点窥视或篡改,HTTPS 可以保证数据传输的保密性、完整性和不被冒充;
    • 正因为 HTTPS 传输的数据对中间节点保密,所以它具有更好的连通性。基于 HTTPS 部署的新协议具有更高的连接成功率;
    • 当前主流浏览器,都只支持基于 HTTPS 部署的 HTTP/2;

    如果前面两个原因还不足以说服你,最后这个绝对有说服力,除非你的 HTTP/2 服务只打算给自己客户端用。

    下面介绍在 HTTPS 中,浏览器和服务端之间怎样协商是否使用 HTTP/2。

    基于 HTTPS 的协议协商非常简单,多了 TLS 之后,双方必须等到成功建立 TLS 连接之后才能发送应用数据。而要建立 TLS 连接,本来就要进行 CipherSuite 等参数的协商。引入 HTTP/2 之后,需要做的只是在原本的协商机制中把对 HTTP 协议的协商加进去。

    Google 在 SPDY 协议中开发了一个名为 NPN(Next Protocol Negotiation,下一代协议协商)的 TLS 扩展。随着 SPDY 被 HTTP/2 取代,NPN 也被官方修订为 ALPN(Application Layer Protocol Negotiation,应用层协议协商)。二者的目标和实现原理基本一致,这里只介绍后者。如图:

    图片 5

    可以看到,客户端在建立 TLS 连接的 Client Hello 握手中,通过 ALPN 扩展列出了自己支持的各种应用层协议。其中,HTTP/2 协议名称是 h2

    图片 6

    如果服务端支持 HTTP/2,在 Server Hello 中指定 ALPN 的结果为 h2 就可以了;如果服务端不支持 HTTP/2,从客户端的 ALPN 列表中选一个自己支持的即可。

    并不是所有 HTTP/2 客户端都支持 ALPN,理论上建立 TLS 连接后,依然可以再通过 HTTP Upgrade 进行协议升级,只是这样会额外引入一次往返。

    Drop


    其次我们需要明确被拖动元素可放置的位置,ondragover 事件规定在何处放置被拖动的数据。
    默认地,无法将元素放置到其他元素中,如果需要设置允许放置,我们必须阻止对元素的默认处理方式:

    var dus = document.querySelector('.dustbin'); dus.ondragover = function(e) { e.preventDefault(); };

    1
    2
    3
    4
    5
    var dus = document.querySelector('.dustbin');
     
    dus.ondragover = function(e) {
      e.preventDefault();
    };

    当元素被拖动到某一元素上时,即会触发后者的 ondrop 事件,如果需要正确触发 ondrop 事件,还需要取消一些 DnD 事件的默认行为:

    dus.ondrop = function(e) { // 调用 preventDefault() 来避免浏览器对数据的默认处理(drop 事件的默认行为是以链接形式打开) e.preventDefault(); e.stopPropagation(); // 兼容ff var id = e.dataTransfer.getData('id') , node = document.getElementById(id); node.parentNode.removeChild(node); };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    dus.ondrop = function(e) {
      // 调用 preventDefault() 来避免浏览器对数据的默认处理(drop 事件的默认行为是以链接形式打开)
      e.preventDefault();
      e.stopPropagation(); // 兼容ff
     
      var id = e.dataTransfer.getData('id')
        , node = document.getElementById(id);
     
      node.parentNode.removeChild(node);
    };

    有些文献中说要取消 ondragenter() 事件的默认行为,楼主在实际操作中并未发现这点。

    启用 HSTS

    HSTS,HTTP Strict Transport Security,简单说就是强制客户端使用 HTTPS 访问页面。其原理就是:

    • 在服务器响应头中添加  Strict-Transport-Security ,可以设置  max-age
    • 用户访问时,服务器种下这个头
    • 下次如果使用 http 访问,只要 max-age 未过期,客户端会进行内部跳转,可以看到 307 Redirect Internel 的响应码
    • 变成 https 访问源服务器

    这个过程有效避免了中间人对 80 端口的劫持。但是这里存在一个问题:如果用户在劫持状态,并且没有访问过源服务器,那么源服务器是没有办法给客户端种下 Strict-Transport-Security  响应头的(都被中间人挡下来了)。

    启用 HSTS 不仅仅可以有效防范中间人攻击,同时也为浏览器节省来一次 302/301 的跳转请求,收益还是很高的。我们的很多页面,难以避免地出现 http 的链接,比如 help 中的链接、运营填写的链接等,这些链接的请求都会经历一次 302,对于用户也是一样,收藏夹中的链接保存的可能也是 http 的。

    本文由奥门新浦京网址发布于Wed前段,转载请注明出处:让拖放变的流行起来,你所不知道的

    关键词:

上一篇:移动端自适应方案,CSS布局奇技淫巧

下一篇:没有了