关于协议:QUIC-协议特性应用场景及其对物联网车联网的影响

什么是 QUIC 协定QUIC(Quick UDP Internet Connections)是由谷歌公司开发的一种基于用户数据报协定(UDP)的传输层协定,旨在进步网络连接的速度和可靠性,以取代以后互联网基础设施中宽泛应用的传输控制协议(TCP)。 QUIC 通过加密和多路复用技术来提供更高的安全性和更快的数据传输。它反对在单个连贯上并行发送多个数据流,从而升高提早并进步吞吐量。QUIC 还具备拥塞管制和流量管制等机制,以应答网络拥塞并保障数据传输的稳定性。 残缺内容请点击下方链接查看: https://developer.aliyun.com/article/1233230?utm_content=g_10... 版权申明:本文内容由阿里云实名注册用户自发奉献,版权归原作者所有,阿里云开发者社区不领有其著作权,亦不承当相应法律责任。具体规定请查看《阿里云开发者社区用户服务协定》和《阿里云开发者社区知识产权爱护指引》。如果您发现本社区中有涉嫌剽窃的内容,填写侵权投诉表单进行举报,一经查实,本社区将立即删除涉嫌侵权内容。

June 27, 2023 · 1 min · jiezi

关于协议:DatenLord|Curp-共识协议的重新思考

共识简介共识协定是一种让分布式系统中多个节点放弃信息统一的通信协议,即便多数节点产生故障也仍然可能保障信息的精确和统一。而每当咱们在探讨共识协定的时候往往会想到 classic paxos 或者 raft 协定,这两个协定是很多其余协定的根底,后续的很多协定都能够看成是它们的变种,例如 Multi-Paxos和 Fast-Paxos等等。咱们明天先从这两个协定动手,先来回顾一下这两个协定是如何工作的。 首先来看 classic paxos 协定,如下图所示。Paxos 分为两个阶段(Phase),第一个阶段是 Prepare,次要工作是在 Log 上占一个 Slot,第二个阶段为 Accept,次要是确定这个 Slot 曾经明确被占用了,且在两个阶段间没有被其他人抢占。当 Client 收到绝大多数人的 Accept Ok 回复之后,阐明该条记录曾经被提交,在整个零碎达成了共识。这里 Client 和 Proposer 能够视为一个整体,整个过程在两个阶段别离有一次消息传递,总共产生两次消息传递。 而后咱们再看 raft 协定,如下图所示。Raft 也是通过 Client 来发动,Client 向 Leader 发送申请,Leader 将申请播送给所有 Follower,当超过半数 Follower 回复音讯,Leader 确定该申请被提交,而后将音讯回复给 Client。这里 Client 和 Leader 之间进行了一消息传递,Leader 和 Follower 之间进行了一次消息传递,总共产生了两次消息传递。 咱们发现在上述的两个协定中,想要达成共识就必须要通过两次消息传递。两次消息传递在数据中心外部还不会造成太大的影响,增大的申请提早往往还能够承受,然而在跨数据中心的场景下,每多一次消息传递就减少几十甚至上百毫秒的提早,所以减小消息传递的数目在跨数据中心的场景下就十分必要。接下去大家肯定会问“两次音讯是必要的的吗”?答复是在 Raft 和 Classic Paxos 的条件下,两次消息传递是必须的,因为他们同时保障了两个个性: 申请一旦被 commit,则不会被批改或者失落。申请执行程序一旦被确定,程序也不会被批改或失落。想要同时保障这两个个性,一次消息传递肯定不够。在 paxos 这种无 Leader 的协定中,一次消息传递只能保障绝大多数节点收到的了申请,那么第 1 个个性可能放弃,然而多个申请间的程序没有方法在多节点间保持一致,毁坏了第 2 个个性。在 Raft 这种有 Leader 的协定中,一次消息传递只能让 Leader 确定执行程序,也就是第 2 个个性,但无奈保障该申请不会失落,因为此时只有 Leader 节点获悉这个申请。 ...

July 20, 2022 · 2 min · jiezi

关于协议:EIP4626-Tokenized-Vault-Standard-金库标准化

https://eips.ethereum.org/EIP...Abstract以下规范容许为代表单个底层 ERC-20 份额的保险库施行规范 API。 该规范是 ERC-20 代币的扩大,它提供了存取代币和读取余额的基本功能。 Motivation代币化保险库不足标准化,导致施行细节多样化。 一些不同的例子包含借贷市场、聚合器和具备外在利息的代币。 这使得须要合乎许多规范的协定在聚合器或插件层难以集成,并迫使每个协定实现本人的适配器,这些适配器容易出错并节约开发资源。代币化保险库的规范将升高收益保险库的集成工作量,同时创立更加统一和弱小的施行模式。 CodeEventsDeposit事件: event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);Withdraw事件: event Withdraw( address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares);IMMUTABLESERC20 public immutable asset;constructor( ERC20 _asset, string memory _name, string memory _symbol) ERC20(_name, _symbol, _asset.decimals()) { asset = _asset;}Main LogicDeposit函数:function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares) { // Check for rounding error since we round down in previewDeposit. require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES"); // Need to transfer before minting or ERC777s could reenter. asset.safeTransferFrom(msg.sender, address(this), assets); _mint(receiver, shares); emit Deposit(msg.sender, receiver, assets, shares); afterDeposit(assets, shares);}Mint函数: ...

March 19, 2022 · 3 min · jiezi

关于协议:认识流媒体协议从-RTSP-协议解析开始

RTSP 是 Internet 协定标准,是 TCP/IP 协定体系中的一个应用层协定级网络通信零碎。专为娱乐(如音频和视频)和通信零碎的应用,以管制流媒体服务器。该协定用于在端点之间建设和管制媒体会话。媒体服务器的客户端收回 VHS 款式的命令,例如:PLAY、PAUSE、SETUP、DESCRIBE、RECORD 等等。以促成对从服务器到客户端或从客户端到服务器的媒体流进行实时控制。 RTSP 传输过程 当用户或应用程序尝试从近程源流式传输视频时,客户端设施会向服务器发送 RTSP 申请,以确定可用选项,例如 PLAY,PAUSE、SETUP。。。而后,服务器返回它能够通过 RTSP 承受的申请类型的列表。客户端晓得如何发出请求后,便将媒体形容申请发送到流服务器。服务器以媒体形容作为响应。客户端从那里发送设置申请,服务器以无关传输机制的信息作为响应。设置过程实现后,客户端将通过通知服务器应用设置申请中指定的传输机制发送位流(二进制序列)来启动流传输过程。客户端 ->服务器:DESCRIBE 服务器 ->客户端: 200 OK (SDP) 客户端 ->服务器:SETUP 服务器 ->客户端: 200 OK 客户端 ->服务器:PAUSE ... 协定的剖析和学习少不了抓包,截屏个 RTSP 协定抓包的图: 为什么 RTS 协定那么重要 RTSP 最后是一种容许用户间接从 Internet 播放音频和视频,而不用将媒体文件下载到其设施的办法。该协定已被利用于多种用处,包含互联网摄像机站点,在线教育和互联网播送。RTSP 应用与根本 HTTP 雷同的概念,在很大水平上是为了兼容现有的 Web 根底构造。正因如此,HTTP 的扩大机制大都能够间接引入到 RTSP 中。RTSP 协定还具备很大的灵活性。客户端能够申请他们要应用的性能,以找出媒体服务器是否反对它们。同样,领有媒体的任何人都能够从多个服务器传递媒体流。该协定还旨在适应媒体的将来倒退,以便媒体创建者能够在必要时批改协定。RTSP 协定指令 只管 RTSP 在某些方面相似于 HTTP,但它定义了可用于管制多媒体播放的管制序列。只管 HTTP 是无状态的,但 RTSP 却具备状态。 在须要跟踪并发会话时应用标识符。像 HTTP 一样,RTSP 应用 TCP 来保护端到端连贯,端口号为 554。 ...

October 8, 2021 · 5 min · jiezi

关于协议:测试开发之网络篇常用服务协议

协定,是网络协议的简称,网络协议是通信计算机单方必须独特听从的一组约定。如怎么样建设连贯、怎么样相互辨认等。只有恪守这个约定,计算机之间能力互相通信交换。它的三要素是:语法、语义、时序。(1)语法:即数据与管制信息的构造或格局;(2)语义:即须要收回何种管制信息,实现何种动作以及做出何种响应;(3)时序(同步),即事件实现程序的具体阐明。 TCP/IPTCP/IP协定是当今互联网所采纳的协定。它不仅蕴含TCP、IP两个局部,而是由FTP、SMTP、TCP、UDP、IP等协定形成的一个协定簇。TCP/IP协定的第4层-网络层,负责创立主机间的网络连接,以及实现基于IP的寻址和转发性能。 DNSDNS(Domain Name System,域名零碎)是一项域名解析服务。它将域名解析成IP地址,以不便大家应用容易记忆的英文字母,来拜访互联网。以下示例实现了一次解析,通过ping域名,咱们能够失去其IP地址。 本地域名解析 除了借助DNS,当咱们通过域名拜访外部服务器时,可应用本地的HOSTS文件来实现域名解析,留神这个过程是优先于DNS的。Windows下文件为C:\WINDOWS\system32\drivers\etc\hosts,Linux下在/etc/hosts,以下给出一个示例。 DHCPDHCP(Dynamic Host Configuration Protocol,动静主机配置协定)用于给局域网中的主机动态分配可用的IP地址。在Windows下,应用ipconfig命令,能够查看本机所调配的IP地址,Linux下请应用ifconfig代替。 此处显示了两个IP地址: lo0 127.0.0.1 是用于本机外部通信的环回地址。它是一个每台机器都雷同、永远无效的虚拟机本地IP地址;en0 192.168.0.100 是DHCP服务器为第一块以太网卡调配的动静IP地址。机器关机后,DHCP会为该机器(网卡)保留此地址一段时间。HTTP/HTTPSHTTP(HyperText Transfer Protocol,超文本传输协定)是互联网上应用最为宽泛的一种协定。您正在应用浏览器浏览的这篇文章,就是应用该协定传输的。HTTPS则是在其根底上,实现了加密。HTTP/HTTPS是一个无连贯、无状态的应用层协定。也就是说,浏览器通过它向服务器发出请求获取响应后,连贯就被敞开了。浏览器和服务器间,采纳了一个叫做Session(会话)的机制,使得下一个申请过去时,服务器仍然晓得访问者是谁。服务端辨认Session的办法,通常是用申请URL或Header中携带的一个惟一标识(如jsessionid、bearer token、cookie)来起作用的。后续在介绍接口测试时,咱们会进一步进行论述。 WebSocketWebSocket在客户端和服务器之间建设持久性的连贯,容许服务端被动向客户端推送数据,以实现实时的双向数据传输。它解决了以往应用HTTP协定时,只能单项拉数据,或应用HTTP模仿长连贯时,Long Polling资源耗费过大的问题。WebSocket是应用层协定,是TCP/IP协定的子集,它在连贯时通过HTTP协定实现握手。 RPCRPC(Remote Procedure Call Protocol,近程过程调用协定)多用于当下风行的微服务架构中,不便一台计算机间接调用另一台上的程序,而不须要理解底层的网络技术/协定。RPC能够基于HTTP(应用层)协定,也能够间接在TCP(传输层)协定上实现

June 18, 2021 · 1 min · jiezi

关于协议:网络分层模型四层和七层

网络分层模型-四层和七层OSI网络分层模型开放式系统互联模型 (Open System Interconnection Model) 是一种概念模型,由国际标准化组织提出,一个试图使各种计算机在世界范畴内互连为网络的规范框架。定义于ISO/IEC 7498-1。 层数名称7应用层(Application)6表示层(Presentation)5会话层(Session)4传输层(Transport)3网络层(Network)2数据链路层(Data link)1物理层(Physical)第七层应用层作用:应用层并不是应用程序,而是为应用程序提供服务。次要解决不同应用程序间的通信问题。常见协定:http、ftp、dhcp、pop3、smtp、ssh第六层表示层作用:把数据转换为能与接收者的零碎格局兼容并适宜传输的格局,例如转换、压缩和加密。常见协定:ssl第五层会话层作用:负责在数据传输中设置和保护计算机网络中两台计算机之间的通信连贯,为创立、治理和终止会话提供必要的办法。第四层传输层作用:传输层提供数据传输的服务,这里的“传输”指的是端对端(End-to-End)或者主机对主机(Host-to-Host)的传输。常见协定:tcp、udp第三层网络层作用:网络层关怀的次要是如何把数据从一个设施发送到另一个设施。网络层须要提供三个最根本的性能:地址、路由、分段和重组。同时还须要一些附加的性能,比方错误处理和诊断。常见协定:ipv4/ipv6第二层数据链路层作用:数据链路层又分为两个子层:逻辑链路管制层(Logical Link Control)和介质访问控制层(Media Access Control)。负责网络寻址、谬误侦测和改错。第一层物理层作用:物理层在部分局域网上发送数据帧(Data Frame),它负责管理电脑通信设施和网络媒体之间的互通。包含了针脚、电压、线缆标准、集线器、中继器、网卡、主机接口卡等。TCP/IP网络分层模型TCP/IP网络分层模型是一个形象的分层模型,这个模型中,所有的TCP/IP系列网络协议都归类到4个形象的“层”中。每一形象层创立在低一层提供的服务上,并且为高一层提供服务。 这些协定散布在参考模型的不同层中的,因而有时称它们为一个协定栈。 层数名称4应用层(Application)3传输层(Transport)2网络互联层(Internet)1链接层(link)End...

June 3, 2021 · 1 min · jiezi

snkrs-协议分析

nike snkrs 分析原文地址:https://github.com/zhaojunlik... snkrs bot api 该项目只提供演示api调用结果,目前实现功能: [x] 登录[x] 注册[x] 抢货[x] AI 真人模拟[x] cookies生成[x] akamai AI风控过检[x] 自动养号,代理IP 登录流程: 1.访问登录页面set-cookie: bm_sz=B37D70D8485724389F741A447D64272E~YAAQBWgDF6U8cJptAQAAW/fEngVzLQr34OcGkuRpuk4fkQXEwRg5Lm5HNVt/eX6LN3+MqPSQ8xRfoEtv8nKjfH+BIoPT1zlo5jKXftf04XKsq1I+ZxKjIpmcx7Eg8rxrVPOjmsMt9t73rkY722b2+xtnuf/Gp1ABBh6n+b4jDgKIbBQhEx/b5sPSUryZsVtToQ==; Domain=.nikecdn.com; Path=/; Expires=Sun, 06 Oct 2019 05:52:51 GMT; Max-Age=14400; HttpOnlyset-cookie: _abck=7FA9F8070CB4ECCF0D932306A0EE19EC~-1~YAAQBWgDF6Y8cJptAQAAW/fEngLnhueJqG/zWlL5St0uvc7Jq4H1rTTH+m5g7BInjI/x7P6G6wS1NU5+XlKM+mjRpQspjqGPcnc2p3btMBL5IjdLvoABWU5QeH2AWQW4zd0ko9s4d342xm5nebmCAt9Hg43UJsDHHFB5msUW+NlsM+0+qGsGxS3NDlagvxboOnOPG3TER3lj+4/gPO5IxVoS5zP5K3hJm8pFLhUOKA7oLD6D+6U4AcXwmlpdWy1Gm6vvU/Epz9S9lKWP5t/ZHEom/Pp4/NK4XWho9/ug4P0lCpAV2Vk50ZsIHw==~-1~-1~-1; Domain=.nikecdn.com; Path=/; Expires=Mon, 05 Oct 2020 01:52:51 GMT; Max-Age=31536000; Secure2.注册cookie到sensor_dataGETcookie: bm_sz=B37D70D8485724389F741A447D64272E~YAAQBWgDF6U8cJptAQAAW/fEngVzLQr34OcGkuRpuk4fkQXEwRg5Lm5HNVt/eX6LN3+MqPSQ8xRfoEtv8nKjfH+BIoPT1zlo5jKXftf04XKsq1I+ZxKjIpmcx7Eg8rxrVPOjmsMt9t73rkY722b2+xtnuf/Gp1ABBh6n+b4jDgKIbBQhEx/b5sPSUryZsVtToQ==cookie: _abck=7FA9F8070CB4ECCF0D932306A0EE19EC~-1~YAAQBWgDF6Y8cJptAQAAW/fEngLnhueJqG/zWlL5St0uvc7Jq4H1rTTH+m5g7BInjI/x7P6G6wS1NU5+XlKM+mjRpQspjqGPcnc2p3btMBL5IjdLvoABWU5QeH2AWQW4zd0ko9s4d342xm5nebmCAt9Hg43UJsDHHFB5msUW+NlsM+0+qGsGxS3NDlagvxboOnOPG3TER3lj+4/gPO5IxVoS5zP5K3hJm8pFLhUOKA7oLD6D+6U4AcXwmlpdWy1Gm6vvU/Epz9S9lKWP5t/ZHEom/Pp4/NK4XWho9/ug4P0lCpAV2Vk50ZsIHw==~-1~-1~-1x-requested-with: com.nike.snkrs3.上传用户数据post4.进行登录cookie: bm_sz=B37D70D8485724389F741A447D64272E~YAAQBWgDF6U8cJptAQAAW/fEngVzLQr34OcGkuRpuk4fkQXEwRg5Lm5HNVt/eX6LN3+MqPSQ8xRfoEtv8nKjfH+BIoPT1zlo5jKXftf04XKsq1I+ZxKjIpmcx7Eg8rxrVPOjmsMt9t73rkY722b2+xtnuf/Gp1ABBh6n+b4jDgKIbBQhEx/b5sPSUryZsVtToQ==cookie: _abck=7FA9F8070CB4ECCF0D932306A0EE19EC~-1~YAAQBWgDF8A+cJptAQAAwTXFngKDLhcRfNXmKGRrcQj7GMBLX8ceaRQv3rrGvdx8bRxveQWFZIH/7UHoyZiITOYI3fRwGXXeoXxfEvLmuJb8KWC5Mba+ZLtzlDtdOXdkSOlwGxZK6GnnZW2Vw/YlfXhMovfyUdGnhtjDYDQWM9OpZvBupfHkpYkDbkj8wSd9+1TNjSRe/oKNLGCyrIVG6NE2EjfXtjVhdxwsV0R8sEm8k1+Tz3l7BSbTtETFM4h0ZQz7aLzKJjx2m5sBV3Zw2zYzhKNi7qRIuwY4xHcPFBAfYfkB1AKX2hXRRM7xjsxEmLT7Vh5VU6Nh/SFLGfVmYtPy/37J~-1~-1~-1x-requested-with: com.nike.snkrs//可能,如果登录失败,要么切换设备ID,要么上传错误信息后拿到cookie重新登录https://unite.nike.com/error?platform=android&browser=uniteSDK&mobile=true&native=true&uxid=com.nike.commerce.snkrs.droid&locale=zh_CN&osVersion=24&sdkVersion=2.8.1&backendEnvironment=identity&url=https%3A%2F%2Fs3.nikecdn.com%2Flogin%3FappVersion%3D638%26experienceVersion%3D638%26uxid%3Dcom.nike.commerce.snkrs.droid%26locale%3Dzh_CN%26backendEnvironment%3Didentity%26browser%3DGoogle%2520Inc.%26os%3Dundefined%26mobile%3Dtrue%26native%3Dtrue%26visit%3D1%26visitor%3Dc36c3bfa-6700-43cd-bc7b-72a23c398b34&errorMsg=HTTP+error+message%3A++and+code%3A+401协议开放API列表 下面是部分任务截图 架构1.nodejs api端提供web服务 2.golang 消息队列消费任务 租用资源联系我 计划1.开放部分API2.支付宝自动扫码付款插件(开放源代码)3.订单后续实时同步查询状态协议授权协议:只允许研究、学习目的的分享、使用、修改,不允许任何商业用途。转载请注明出处,感谢。

October 14, 2019 · 1 min · jiezi

IPUDP和TCP的关系

互联网,实际上是一套理念和协议组成的体系架构。其中,协议是一套众所周知的规则和标准,如果各方都同意使用,那么它们之间的通信将变得毫无障碍。 IP:把数据包送达目的主机数据包要在互联网上进行传输,就要符合网际协议(IP)标准,互联网上不同的在线设备都有唯一的地址,地址只是一个数字,这和大部分家庭收件地址类似,你只需要知道一个家庭的具体地址,就可以往这个地址发送包裹,这样物流系统就能把物品送到目的地。 计算机的地址就称为 IP 地址,访问任何网站实际上只是你的计算机向另外一台计算机请求信息。 如果要想把一个数据包从主机 A 发送给主机 B,那么在传输之前,数据包上会被附加上主机 B 的 IP 地址信息,这样在传输过程中才能正确寻址。额外地,数据包上还会附加上主机 A 本身的 IP 地址,有了这些信息主机 B 才可以回复信息给主机 A。这些附加的信息会被装进一个叫 IP 头的数据结构里。IP 头是 IP 数据包开头的信息,包含 IP 版本、源 IP 地址、目标 IP 地址、生存时间等信息。 简化的 UDP 网络三层传输模型 UDP:把数据包送达应用程序IP 是非常底层的协议,只负责把数据包传送到对方电脑,但是对方电脑并不知道把数据包交给哪个程序,是交给浏览器还是交给王者荣耀?因此,需要基于 IP 之上开发能和应用打交道的协议,最常见的是“用户数据包协议(User Datagram Protocol)”,简称UDP。 UDP 中一个最重要的信息是端口号,端口号其实就是一个数字,每个想访问网络的程序都需要绑定一个端口号。通过端口号 UDP 就能把指定的数据包发送给指定的程序了,所以IP 通过 IP 地址信息把数据包发送给指定的电脑,而 UDP 通过端口号把数据包分发给正确的程序。和 IP 头一样,端口号会被装进 UDP 头里面,UDP 头再和原始数据包合并组成新的 UDP 数据包。UDP 头中除了目的端口,还有源端口号等信息。 简化的 UDP 网络四层传输模型 UDP 不能保证数据可靠性,但是传输速度却非常快,所以 UDP 会应用在一些关注速度、但不那么严格要求数据完整性的领域,如在线视频、互动游戏等。 ...

August 20, 2019 · 1 min · jiezi

ShardingSphere-x-Seata一致性更强的分布式数据库中间件

日前,分布式数据库中间件 ShardingSphere 将 Seata 分布式事务能力进行整合,旨在打造一致性更强的分布式数据库中间件。 背景数据库领域,分布式事务的实现主要包含:两阶段的 XA 和 BASE 柔性事务。XA 事务底层,依赖于具体的数据库厂商对 XA 两阶段提交协议的支持。通常,XA 协议通过在 Prepare 和 Commit 阶段进行 2PL(2 阶段锁),保证了分布式事务的 ACID,适用于短事务及非云化环境(云化环境下一次 IO 操作大概需要 20ms,两阶段锁会锁住资源长达 40ms,因此热点行上的事务的 TPS 会降到 25/s 左右,非云化环境通常一次 IO 只需几毫秒,因此锁热点数据的时间相对较低)。 但在 BASE 柔性事务方面,ShardingSphere 提供的接入分布式事务的 SPI,只适用于对性能要求较高,对一致性要求比较低的业务。 Seata 核心的 AT 模式适用于构建于支持本地 ACID 事务的关系型数据库。通过整合 Seata,其 AT 模式在一阶段提交+补偿的基础上,通过 TC 的全局锁实现了 RC 隔离级别的支持,可提高 ShardingSphere 的分布式事务的一致性。 整合方案整合 Seata AT 事务时,需要把 TM,RM,TC 的模型融入到 ShardingSphere 分布式事务的 SPI 的生态中。在数据库资源上,Seata 通过对接 DataSource 接口,让 JDBC 操作可以同 TC 进行 RPC 通信。同样,ShardingSphere 也是面向 DataSource 接口对用户配置的物理 DataSource 进行了聚合,因此把物理  DataSource 二次包装为 Seata 的 DataSource 后,就可以把 Seata AT 事务融入到 ShardingSphere 的分片中。 ...

July 4, 2019 · 1 min · jiezi

高并发架构的HTTP知识介绍

我们前面说过了 CDN的知识,也通过抓包分析了 TCP建立链接的过程。今天一起聊一聊应用层的协议 HTTP/HTTPS;这是应用工程师日常中接触最久的协议了。但是你真的了解他吗? 今天我们不讲 HTTP协议 的几种请求方式,主要介绍HTTP及HTTPS整个发送数据的过程。 消息结构还记得前面讲的 DNS 的过程吗?通过DNS我们拿到了服务端的IP地址,然后通过TCP协议,完成了浏览器与应用服务器的连接建立。HTTP协议是建立在TCP协议之上的(上层协议必然依赖下层协议),连接建立后,自然是开始通信。那么通信的格式是什么呢? 看上面这张图,HTTP的请求与响应格式基本如此。我们分开来说。 对于 请求消息 ,由三部分构成:请求行、请求头、请求的Body;所谓的请求行,就是:POST / HTTP/1.1 这部分内容。接下来的就是请求头,也就是我们常说的HTTP头;然后换行后紧接着的内容就是请求的Body,也就是正儿八经发送给应用的参数。 对于 响应消息 ,也是由三部分构成:状态行、响应头、响应的Body;关于响应行就是标记本次请求获得的结果是什么,这里主要有:20X、30X、40X、50X这几个范围的状态码,需要熟记。响应头里边重要的主要有跟缓存相关的东西,这部分内容会知道浏览器、CDN等缓存体的缓存行为,需要有一定的了解;最后的实体就是你请求的想要的结构,比如:HTML、Json等等。 传输过程消息构建后,如何发送进行传输呢?我们上面图片中看到的是字符串内容,HTTP本身是不能进行网络传输的,它必须依赖的底层的TCP协议建立的连接来发送数据。因此它实际上就是把这些构建好的字符串传给下层的TCP,至于TCP如何传输的可以看上篇文章,这里不展开了。 WebService 收到数据后会对数据进行处理然后交给应用服务器,应用服务器自然是将请求的Body作为输入,然后根据要求产生输出。输出的行为受到请求头中部分信息的控制,比如:格式(Content-Type)、编码(Accept-Charset)等。而产生的输出各个地方也会根据响应头进行处理。 看到这里大家有没有发现几个问题:HTTP依赖底层的TCP连接,也就是每个HTTP都需要进行三次握手,效率是不是会非常慢?这种方式总需要浏览器端主动发起链接,服务端想主动推送些什么很无能为力; 针对上面这些问题,HTTP2.0 协议也就诞生了,当然上面这些问题在 HTTP1.1 时代也有些解决方案。HTTP2.0 主要解决了协议头进行压缩,传输同样含义的内容,占用带宽更少速度更快;将上面的单向链接的方式改成二进制流的方式,服务端有能力主动推送数据;一个链接里边支持传输多种数据流。 关于 HTTP2.0 的内容不是文本主要想说的,大家可以自行了解下。接下来又到了 核心部分,关于 HTTPS 为什么安全、以及如何加密的解释。这部分内容算是面试的重要考点。 HTTPS为什么可靠现在大网站基本都适用了HTTPS协议,那么它跟HTTP是什么关系呢?它其实就是HTTP加上TLS(SSL)安全层,合在一起就叫 HTTPS。为什么有了这层处理数据就安全了呢? 很简单,要想安全就得加密。加密的方式现在无非就是:对称加密 与 非对称加密。 对称加密: 加密与解密都是使用相同的密钥,因此这种方式加密数据,密钥一定不能丢失。 非对称加密: 有两把密钥,私钥与公钥。使用私钥加密的数据必须使用公钥进行解密,反之依然。 安全的代价看起来 非对称加密 非常安全。不过对称加密的效率非常高。HTTPS正是综合使用这两种加密方式,让整个传输过程变得安全。接下来看看这个过程是如何完成的。 对称加密我们先来看看,如果HTTPS只使用 对称加密,能否满足安全的需要呢?由于这种情况只有一个密钥,服务端怎么把这个密钥交给客户端呢?线上传输肯定会泄漏。 所以单单有对称加密是不能满足需求。看来得换个路子。 非对称加密使用非对称加密的私钥加密数据,发给客户端。客户端用公钥解密就得到了数据。看起来好像没有什么问题。 但是这里有个问题,由于服务端发出来的数据是使用的私钥,由于公钥是公开,这相当于没有加密。大家都能够看到。并且服务端发出去的公钥这个过程也可能被串改啊,你怎么知道你收到的公钥就是服务器给你的呢?就跟现在很多诈骗公司一样,看起来有模有样,实则就是一皮包公司。 第三方公正为了解决上述问题,出现了一个所谓的 CA 机构,它怎么解决这个信任问题呢?它将服务器的公钥放到 CA证书 里边传给客户端(这里指浏览器),浏览器拿到后验证一下这个证书是否真实有效,因为CA机构是有限可追溯的。就跟你的护照一样,可辨别真伪,所以CA证书证明了有效,那么CA证书中携带的公钥自然也证明了自己的身份。 是不是看起来整个过程非常麻烦?没有办法为了安全,这点代价非常值得。这也是为什么我们常常说HTTPS的效率略低于HTTP的原因。 工作模式了解完上面的知识,我们来看看HTTPS到底是如何工作的? 客户端发起了一个https请求,包含版本信息,加密套件候选列表,压缩算法候选列表,随机数random_c,扩展字段等信息。这个过程此时是明文的。然后服务器会进行回复,根据客户端支持的算法信息、套件等,服务器选择一个告诉客户端,我们就用这个吧,同时也会返回一个随机数random_s,后面协商密钥有用。服务端响应客户端,这个响应中包含了证书的链接,用于交换密钥。客户端对收到的数据进行检查,先把证书给拉下来,然后检查各种指标,如果不合法,会看到浏览器提醒不安全。如果验证通过,就会生成一个 随机数字 Pre-master,并用证书公钥加密(非对称加密),发送给服务器。 此时的客户端已经有了生成证书的全部内容,它会计算协商的密钥(对称密钥),然后告诉服务端以后通信都采用协商的通信密钥和加密算法进行加密通信。紧接着会用协商的密钥加密一段数据发给服务端,看看是否能够正常。上面这步里边,客户端发送了三个请求。服务器先将收到的 Pre-master 用自己的私钥解密出来。然后验证客户端用对称加密发过来的数据,如果通过,则也会告知客户端后续的通信都采用协商的密钥与算法进行加密通信。并且服务端也会用对称加密生成一段加密信息给客户端让客户端试试(对称密钥)。客户端使用对称密钥正确完成解密。握手结束。开始使用对称密钥的方式进行数据传输。总结由于不让文章显得过于复杂,我只介绍了最简单的单向认证。这种安全性并不是最高,单日常中也足够了。 ...

June 24, 2019 · 1 min · jiezi

Swoole-多协议-多端口-的应用

概述这是关于 Swoole 学习的第五篇文章:Swoole 多协议 多端口 的应用。 第四篇:Swoole HTTP 的应用第三篇:Swoole WebSocket 的应用第二篇:Swoole Task 的应用第一篇:Swoole Timer 的应用主要参考官方的这两篇文章,进行实现的 Demo。 网络通信协议设计:https://wiki.swoole.com/wiki/...多端口监听的使用:https://wiki.swoole.com/wiki/...希望通过我提供的 Demo,能够对文档有更加深刻的理解。 网络通信协议设计为什么需要通信协议? 官方:TCP协议在底层机制上解决了UDP协议的顺序和丢包重传问题。但相比UDP又带来了新的问题,TCP协议是流式的,数据包没有边界。应用程序使用TCP通信就会面临这些难题。因为TCP通信是流式的,在接收1个大数据包时,可能会被拆分成多个数据包发送。多次Send底层也可能会合并成一次进行发送。这里就需要2个操作来解决:分包 和 合包,所以TCP网络通信时需要设定通信协议。Swoole 支持了2种类型的自定义网络通信协议 :EOF结束符协议、固定包头+包体协议。 EOF结束符协议 先看下,未设置协议的效果: 发送的每条数据长度都是 23,但在 onReceive 接收数据的时候每次接收的长度不一样,并没有按照想象的方式进行分包。 再看下,设置了EOF结束符协议的效果: 发送的每条数据长度都是 23,在 onReceive 接收数据的时候每次接收的也是 23 ,完美。 主要设置项如下: 'package_max_length' => '8192','open_eof_split' => true,'package_eof' => "\r\n"不做解释,官方文档已经写的很清楚。 示例代码如下: server.php <?phpclass Server{ private $serv; public function __construct() { $this->serv = new swoole_server('0.0.0.0', 9501); $this->serv->set([ 'worker_num' => 2, //开启2个worker进程 'max_request' => 4, //每个worker进程 max_request设置为4次 'dispatch_mode' => 2, //数据包分发策略 - 固定模式 //EOF结束符协议 'package_max_length' => '8192', 'open_eof_split' => true, 'package_eof' => "\r\n" ]); $this->serv->on('Start', [$this, 'onStart']); $this->serv->on('Connect', [$this, 'onConnect']); $this->serv->on("Receive", [$this, 'onReceive']); $this->serv->on("Close", [$this, 'onClose']); $this->serv->start(); } public function onStart($serv) { echo "#### onStart ####".PHP_EOL; echo "SWOOLE ".SWOOLE_VERSION . " 服务已启动".PHP_EOL; echo "swoole_cpu_num:".swoole_cpu_num().PHP_EOL; echo "master_pid: {$serv->master_pid}".PHP_EOL; echo "manager_pid: {$serv->manager_pid}".PHP_EOL; echo "########".PHP_EOL.PHP_EOL; } public function onConnect($serv, $fd) { echo "#### onConnect ####".PHP_EOL; echo "客户端:".$fd." 已连接".PHP_EOL; echo "########".PHP_EOL.PHP_EOL; } public function onReceive($serv, $fd, $from_id, $data) { echo "#### onReceive ####".PHP_EOL; var_dump($data); } public function onClose($serv, $fd) { echo "Client Close.".PHP_EOL; }}$server = new Server();client.php ...

May 15, 2019 · 5 min · jiezi

高并发架构的TCP知识介绍

做为一个有追求的程序员,不能只满足增删改查,我们要对系统全方面无死角掌控。掌握了这些基本的网络知识后相信,一方面日常排错中会事半功倍,另一方面日常架构中不得不考虑的高并发问题,理解了这些底层协议也是会如虎添翼。 本文不会单纯给大家讲讲TCP三次握手、四次挥手就完事了。如果只是哪样的话,我直接贴几个连接就完事了。我希望把实际工作中的很多点能够串起来讲给大家。当然为了文章完整,我依然会从 三次握手 起头。 再说TCP状态变更过程不管是三次握手、还是四次挥手,他们都是完成了TCP不同状态的切换。进而影响各种数据的传输情况。下面从三次握手开始分析。 本文图片有部分来自网络,若有侵权,告知即焚三次握手来看看三次握手的图,估计大家看这图都快看吐了,不过为什么每次面试、回忆的时候还是想不起呢?我再来抄抄这过剩饭吧! 首先当服务端处于 listen 状态的时候,我们就可以再客户端发起监听了,此时客户端会处于 SYN_SENT 状态。服务端收到这个消息会返回一个 SYN 并且同时 ACK 客户端的请求,之后服务端便处于 SYN_RCVD 状态。这个时候客户端收到了服务端的 SYN&ACK,就会发送对服务端的 ACK,之后便处于 ESTABLISHED 状态。服务端收到了对自己的 ACK 后也会处于 ESTABLISHED 状态。 经常在面试中可能有人提问:为什么握手要3次,不是2次或者4次呢? 首先说4次握手,其实为了保证可靠性,这个握手次数可以一直循环下去;但是这没有一个终止就没有意义了。所以3次,保证了各方消息有来有回就足够了。当然这里可能有一种情况是,客户端发送的 ACK 在网络中被丢了。那怎么办? 其实大部分时候,我们连接建立完成就会立刻发送数据,所以如果服务端没有收到 ACK 没关系,当收到数据就会认为连接已经建立;如果连接建立后不立马传输数据,那么服务端认为连接没有建立成功会周期性重发 SYN&ACK 直到客户端确认成功。再说为什么2次握手不行呢?2次握手我们可以想象是没有三次握手最后的 ACK, 在实际中确实会出现客户端发送 ACK 服务端没有收到的情况(上面的情况一),那么这是否说明两次握手也是可行的呢?看下情况二,2次握手当服务端发送消息后,就认为建立成功,而恰巧此时又没有数据传输。这就会带来一种资源浪费的情况。比如:客户端可能由于延时发送了多个连接情况,当服务端每收到一个请求回复后就认为连接建立成功,但是这其中很多求情都是延时产生的重复连接,浪费了很多宝贵的资源。 因此综上所述,从资源节省、效率3次握手都是最合适的。话又回来三次握手的真实意义其实就是协商传输数据用的:序列号与窗口大小。 下面我们通过抓包再来看一下真实的情况是否如上所述。 20:33:26.583598 IP 192.168.0.102.58165 > 103.235.46.39.80: Flags [S], seq 621839080, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1050275400 ecr 0,sackOK,eol], length 020:33:26.660754 IP 103.235.46.39.80 > 192.168.0.102.58165: Flags [S.], seq 1754967387, ack 621839081, win 8192, options [mss 1452,nop,wscale 5,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,sackOK,eol], length 020:33:26.660819 IP 192.168.0.102.58165 > 103.235.46.39.80: Flags [.], ack 1754967388, win 4096, length 0抓包: sudo tcpdump -n host www.baidu.com -S ...

May 7, 2019 · 2 min · jiezi

高并发架构的CDN知识介绍

对一次网络请求过程的了解程度,一是展现你的专业知识;二是深刻的理解,让你在大型网站架构中做出更适合、可靠的架构。而DNS是这一切的出发点,本文结合一张常用架构图,来描述一下这个过程。 部署架构大型的web服务,我们的部署架构一般如下图。先上图再解释。 这里来解释下,为什么要这样架构。首先客户端的请求会通过 DNS 获取到对应的服务器IP(实际上是LB的ip地址),这一层会有 DNS的负载均衡,并且如果是静态站资源会进入到CDN,这里DNS与CDN如何完成接棒的过程,后面会详细解释。当请求到达LB层的时候(应用层协议是HTTP协议),这一层又会做一次负载均衡(可能用LVS或者Nginx做)。这里我们有两种不同的处理方式,一条路径会进入到代理集群,一条路径直接进入到应用集群。这是为什么? LB到代理集群通过最顶层的LB负责均衡后到达代理机器,这里不直接进入到应用集群,还要搞一层代理的目的主要是方便我们在代理集群进行各种高级(骚)操作。 比如:请求日志收集,自定义缓存,自定义的负载均衡,自定义的路由规则制定(跨机房,路由分组) LB到应用集群上面到代理层有那么多好处,为什么还有绕过代理层这条路径存在呢?这主要是针对大流量服务。因为代理层因为有很多额外的操作,导致响应会变长,路径增加,到下一个集群多了一次网络传输往返。 所以,一般针对大流量服务,为了防止代理被打满,响应更快,会直接在外网LB上进行负载到应用集群。 通过上面的分割后,最终都会到达应用集群,每一台机器上我们会部署一台 Nginx 来按照域名转到对应服务,当然这里完全也可以不是 Nginx ,比如微服务,这里可能是一个 SideCard 代理。这里主要是为了便于说明我们后面全部都是当成Nginx。服务调用 DB Cache 等,都是通过域名,这是为了负载均衡,请求时,会通过内网DNS服务,完成域名解析,然后拿到内网的 LB 的IP。然后再这里进行内网的负载均衡,会根据域名的端口来检查你是写操作、还是读操作返回IP。常规一点会保证是单点写入,多点读取。来完成数据一致性的保障。 整个大体过程如此,接下来我们详细说一下 DNS 与 CDN 相关的工作原理。 DNS如何实现IP查找为了后面说清楚CDN,这里先介绍DNS的解析过程。当然此类文章网络上已经极多。但是我还是想按照我的理解来说一下DNS是如何工作的。 在整个DNS过程中有四个重要概念,下面解释下。 DNS Resolver - 递归解析器,主要是接收客户端发出的域名解析请求,并发送 DNS query 查询请求。对于客户端来说它不需要任何操劳,等待 DNS Resolver 告诉自己域名转IP的结果就好。 Root Server - 这是转换IP执行的第一步查询,根服务器并不会保存具体的域名IP映射信息。它就像一个索引服务器,会告诉你下一步该去那台 TLD Server 查询。 TLD Server - 这是顶级域名服务器,是执行IP查询的第二步,这里会告诉 DNS Resolver 权威域名服务器的地址。 Authoriative Server - 权威域名服务器就是包含了完整的机器名的域名,例如:www.example.com ,在这台机器上保存了这个具体域名对应的IP地址。 下面根据图中的十个步骤说一下每一步都在干嘛。 一个用户在浏览器输入了:example.com,这时会产生一个 DNS 查询,从而进入到 DNS Resolver中;Resolver 会进入到 root server 进行查询;root server 返回了 TLD server 的地址,查询请求转向顶级域名服务,这里是 .com 服务器。递归解析器向 .com 服务器发送一个请求;TLD server 收到请求后会返回 example.com 权威服务器的地址;递归解析器又发了一个向权威服务器查询的请求,至此权威服务器查询自己的映射表拿到IP;返回查询到的IP给了 DNS Resolver;DNS Resolver返回IP给浏览器,浏览器将会用这个IP来建立连接,发起请求;客户端通过这个IP地址,发起一个 HTTP 请求;服务器解析请求,并返回数据到浏览器。这里需要补充一点是,上面每一步其实都有DNS缓存的设计。比如: ...

April 30, 2019 · 1 min · jiezi

PHP伪协议总结

参考了这篇文章:php伪协议实现命令执行的七种姿势,并根据自己理解进行了总结,也算是加深一下印象,方便以后使用。file:// 协议条件: allow_url_fopen:off/onallow_url_include :off/on作用:用于访问本地文件系统,在CTF中通常用来读取本地文件的且不受allow_url_fopen与allow_url_include的影响。include()/require()/include_once()/require_once()参数可控的情况下,如导入为非.php文件,则仍按照php语法进行解析,这是include()函数所决定的。说明:file:// 文件系统是 PHP 使用的默认封装协议,展现了本地文件系统。当指定了一个相对路径(不以/、、\或 Windows 盘符开头的路径)提供的路径将基于当前的工作目录。在很多情况下是脚本所在的目录,除非被修改了。使用 CLI 的时候,目录默认是脚本被调用时所在的目录。在某些函数里,例如 fopen() 和 file_get_contents(),include_path 会可选地搜索,也作为相对的路径。用法: /path/to/file.extrelative/path/to/file.extfileInCwd.extC:/path/to/winfile.extC:\path\to\winfile.ext\\smbserver\share\path\to\winfile.extfile:///path/to/file.ext示例: file://[文件的绝对路径和文件名] http://127.0.0.1/include.php?file=file://E:\phpStudy\PHPTutorial\WWW\phpinfo.txt [文件的相对路径和文件名] http://127.0.0.1/include.php?file=./phpinfo.txt [http://网络路径和文件名] http://127.0.0.1/include.php?file=http://127.0.0.1/phpinfo.txt 参考:http://php.net/manual/zh/wrappers.file.phpphp:// 协议条件: allow_url_fopen:off/onallow_url_include :仅php://input php://stdin php://memory php://temp 需要on作用:php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是php://filter和php://input,php://filter用于读取源码,php://input用于执行php代码。说明:PHP 提供了一些杂项输入/输出(IO)流,允许访问 PHP 的输入输出流、标准输入输出和错误描述符,内存中、磁盘备份的临时文件流以及可以操作其他读取写入文件资源的过滤器。 协议作用php://input可以访问请求的原始数据的只读流,在POST请求中访问POST的data部分,在enctype="multipart/form-data" 的时候php://input 是无效的。php://output只写的数据流,允许以 print 和 echo 一样的方式写入到输出缓冲区。php://fd(>=5.3.6)允许直接访问指定的文件描述符。例如 php://fd/3 引用了文件描述符 3。php://memory php://temp(>=5.1.0)一个类似文件包装器的数据流,允许读写临时数据。两者的唯一区别是 php://memory 总是把数据储存在内存中,而 php://temp 会在内存量达到预定义的限制后(默认是 2MB)存入临时文件中。临时文件位置的决定和 sys_get_temp_dir() 的方式一致。php://filter(>=5.0.0)一种元封装器,设计用于数据流打开时的筛选过滤应用。对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、file() 和 file_get_contents(),在数据流内容读取之前没有机会应用其他过滤器。php://filter参数详解 该协议的参数会在该协议路径上进行传递,多个参数都可以在一个路径上传递。具体参考如下: php://filter 参数描述resource=<要过滤的数据流>必须项。它指定了你要筛选过滤的数据流。read=<读链的过滤器>可选项。可以设定一个或多个过滤器名称,以管道符(*\*)分隔。write=<写链的过滤器>可选项。可以设定一个或多个过滤器名称,以管道符(\)分隔。<; 两个链的过滤器>任何没有以 read= 或 write= 作前缀的筛选器列表会视情况应用于读或写链。可用的过滤器列表(4类) 此处列举主要的过滤器类型,详细内容请参考:https://www.php.net/manual/zh/filters.php 字符串过滤器作用string.rot13等同于str_rot13(),rot13变换string.toupper等同于strtoupper(),转大写字母string.tolower等同于strtolower(),转小写字母string.strip_tags等同于strip_tags(),去除html、PHP语言标签转换过滤器作用convert.base64-encode & convert.base64-decode等同于base64_encode()和base64_decode(),base64编码解码convert.quoted-printable-encode & convert.quoted-printable-decodequoted-printable 字符串与 8-bit 字符串编码解码压缩过滤器作用zlib.deflate & zlib.inflate在本地文件系统中创建 gzip 兼容文件的方法,但不产生命令行工具如 gzip的头和尾信息。只是压缩和解压数据流中的有效载荷部分。bzip2.compress & bzip2.decompress同上,在本地文件系统中创建 bz2 兼容文件的方法。加密过滤器作用mcrypt.*libmcrypt 对称加密算法mdecrypt.*libmcrypt 对称解密算法示例: ...

April 26, 2019 · 1 min · jiezi

调用链系列四:调用链上下文传递

在之前的调用链系列文章中,我们已经对调用链进行了详细介绍,相信大家已经对调用链技术有了基本的了解。其实,在调用链的绘制过程中,调用链上下文的传递非常值得关注。各个节点在获取上层上下文后生成新的上下文并向后传递。在传递过程中,上下文一旦丢失或出现异常就会导致调用链数据缺失,甚至可能会发生断裂。本文主要讲述UAV中调用链上下文传递过程中的部分实现细节。前言在调用链的实现中,主要存在以下几种调用链上下文的传递方式:请求处理前到请求处理后的上下文传递;各个客户端调用间的上下文传递;各个服务间调用时的上下文传递。在这三种情况中,上下文传递过程中所传递的信息以及遇到的问题会有所不同。在请求处理前后的上下文传递过程中,需要传递的信息一般包括traceID、 spanID、请求开始的时间以及部分请求参数等。相关代码可能会因为异步执行导致上下文面临异步线程传递的问题。在客户端调用间及服务间调用中,需要传递的上下文信息一般只包括traceID和spanID。但客户端调用之间的上下文传递可能会遇到跨线程池传递的问题,服务间调用则存在跨应用传递的问题。因此,我们把今天所讲的上下文传递划分为以下四种场景进行分析:1、在同一线程内传递2、跨线程池传递3、异步线程传递4、跨应用传递为了更好地阐述这四种场景,我们假设存在以下业务调用过程:假设某次请求首先进入服务A,在服务A的业务代码中发起了一次JDBC请求,访问了一次数据源;然后又通过httpClient(同步,异步)发起了一次http访问并返回相应结果。数字表示所在点存在调用链上下文信息的获取。在大多数的相邻点之间都会涉及到调用链上下文的传递。例如,从2点到3点就是请求前和请求后的上下文传递,从3点到4点就是两次客户端调用间的上下文传递,从4点到5点就是服务间的上下文传递。下面我们将在不同的场景下说明各点之间的上下文传递过程。1.在同一线程内的上下文传递这种场景比较常见,也是最简单的场景。假设上述模拟流程中全部为同步操作,业务代码中不涉及任何的线程池(数据库连接池不影响)及异步操作,那么服务A中调用链的相关代码均会在同一个线程中执行。说到这里,想必大家都会想到使用ThreadLocal便可以解决。使用ThreadLocal的确可以解决同线程中的参数共享传递问题。在UAV中,一般两次客户端调用之间的上下文传递都直接使用ThreadLocal(其实并不是原生的ThreadLocal,后文会有所介绍),传递过程如下:但是很多时候,业务代码中经常会涉及到异步或者提交线程池的操作,此时单单使用ThreadLocal便无法满足相应的需求。下面我们就来讨论有关含有线程池操作和异步请求的上下文传递问题。2.跨线程池的上下文传递首次我们来看一下跨线程池上下文传递问题。假设上述的业务场景中在进行JDBC操作时,当前线程仅负责将JDBC操作提交到线程池中,那么此时上下文信息从1点传递到2点就会遇到跨线程池的问题,此时使用ThreadLocal无法上下文信息的传递。当然有的同学可能会说用InheritableThreadLocal。但是提交线程和线程池线程本身并不存在父子关系,因此InheritableThreadLocal也是无法完成跨线程池的上下文传递的。为了解决这个问题,我们使用了阿里开源的跨线程池的ThreadLocal组件:transmittable-thread-local(以下简称TTL,具体的实现方式有兴趣的同学可以去了解下https://github.com/alibaba/tr…。通过该组件可以增强ThreadLocal的功能实现跨线程池的传递。以下是github中TTL的使用示例:TransmittableThreadLocal<String> parent =newTransmittableThreadLocal<String>();parent.set(“value-set-in-parent”); Runnable task =new Task(“1”);// 额外的处理,生成修饰了的对象ttlRunnableRunnable ttlRunnable = TtlRunnable.get(task);executorService.submit(ttlRunnable);// Task中可以读取,值是"value-set-in-parent"String value = parent.get();可以看到,想要TTL起作用,就需要将业务代码中的runnable更换为TtlRunnable。为了实现对业务代码的零入侵,我们借助javaagent机制增加了一个针对ThreadPoolExecutor等一些Eexecutor的ClassFileTransformer,将提交到线程池中的Runnable和Callable包装成相应的TtlRunnable和TtlCallable,这样就实现了在不修改业务代码的情况下完成跨线程池的上下文传递。另外,由于TTL具备ThreadLocal的所有特性,因此UAV的上下文传递过程中用到的ThreadLocal均是TTL。3.异步线程中上下文传递看完上面的跨线程池操作,我们再来看一下异步线程的问题。假设在上述模拟场景中,我们使用异步HttpClient发送了一个异步的Http请求。由于是异步操作,4点的代码和7点的代码(这里7点的上下文是从4点中获取的属于请求前后的上下文获取场景)实际上会在不同的线程中执行,导致7点无法获取4点放入ThreadLocal中的上下文数据,进而导致调用链的数据丢失。为了解决这个问题,在UAV中我们同时使用了字节码改写和动态代理技术。关键在于目标劫持函数的选择,需要能够获取到异步线程的回调对象。下面以异步HttpClient为例介绍UAV中异步线程上下文的传递过程。在异步HttpClient中,我们劫持的是InternalHttpAsyncClient类的execute()方法,该方法声明如下:一般情况下,异步的使用方式为传入一个callback接口对象,在callback中实现相应的异步逻辑;或者使用返回的Future接口对象的get()方法实现一种异步转同步的操作。为了能够在相应的地方获取到调用链的上下文,我们首先通过改写字节码的方式,在方法执行前生成调用链的上下文信息;然后对FutureCallback接口做动态代理,同时将生成的上下文信息传入到代理对象中,并替换原来的callback对象。这样当异步请求返回调用callback接口时,实际上拿到的是我们的代理对象,此时也就完成了异步线程中上下文的传递过程,具体过程如下:为了支持通过get()方法的异步转同步操作,在这里我们也对返回的Future接口做了动态代理来完成上下文的传递。4.跨应用上下文传递说完应用内的上下文传递过程,我们来看一下跨应用的上下文传递问题。跨应用的场景也是比较常见的。在这种场景下,上下文传递的思路一般是将上下文的信息按照一定的协议反序列化,然后放入到请求的传输报文中;在下游服务中劫持请求,获取其中的信息完成上下文的传递。在整个处理过程中,不对应用报文解析造成任何影响。常见的传输协议中如HTTP协议,Dubbo的RPC协议,RocketMQ的MQ协议等。这些协议一般会含有类似于头信息的结构,用于表示本次请求的额外信息。我们恰好可以利用这一点,将上下文信息放入其中传输给下游服务,完成上下文的传递。下面我们仍然以异步HttpClient来介绍UAV跨应用上下文的传递过程。之前我们说过,在异步HttpClient中,我们劫持的是execute()方法。在这个方法中,我们可以拿到HttpAsyncRequestProducer接口对象,具体接口如下:通过其中的generateRequest()方法,我们就可以拿到本次请求将要发送的request对象,利用request的setHeader()方法,将调用链的上下文信息放入Header中传入下游。这里的上下文一般比较简单,基本上都是由traceID和spanID的字符串构成,传输成本也不高。至于下游服务中如何解析该上下文,实际上之前的调用链系列中有谈到,就是借助UAV的中间件增强框架(MOF),在服务端劫持请求对应的request对象,然后直接从其头信息中获取即可。其他的RPC或者MQ等协议,在UAV中均是采用这种方式完成,只是具体的API和劫持点有所不同。例如,Dubbo远程调用过程中使用是其中的RpcContext,而RocketMQ则是放入到了msg的UserProperty中。感兴趣的同学可以到UAVStack(https://github.com/uavorg/uav…。总结了解这些上下文的传递过程后,大家便可以基于调用链实现更为强大的功能。UAV中,调用链和日志关联功能就是通过劫持日志输入部分的相关代码,获取调用链上下文,然后将traceID输出到业务日志中来实现的。大家也可以自己在业务代码中尝试获取调用链的上下文,将业务数据与调用链数据打通,方便数据统计和问题排查。作者:朱文强 宜信技术学院

February 22, 2019 · 1 min · jiezi

轻松理解OAuth2.0协议(多图)

前言最近有一个简单的需求需要在一个微信公众号外部的H5页面中使用微信登录(接入),同时还要在内部使用第三方支付接口完成支付(不使用微信支付).无奈队友不给力只好自己研究了一下具体的流程,不出意料的是这两个接入商提供的SDK不同另外微观操作不同,但是基本流程是相似的.理解了其中的规则觉得很有意思,边萌生出了使用简单的几张图片来解释OAuth2.0协议的想法.ps:素材是使用note8+autodesk画的,合成使用的是Photoshop,对于我这种手残真的累死了,下次能写字就不发图了( _ ).注意:本文章不是介绍微信以及第三方支付接入具体的实现的文章.什么是OAuth2.0协议(它能干什么)OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。那什么是开放授权,最直接的例子就是在登录一些网站的时候使用第三方账户进行登录,相信这些场景相信大家都再熟悉不过了.为什么使用OAuth2.0协议举一个简单的例子.我们正在维护一个网上商城,当用户点击购买的时候,我们想借用第三方支付来向我们账户里打钱,而不用花巨额的力气再去开发一套支付系统.现在用户点击付钱了你会哪个选项来提供支付功能呢?选项A:<a href=“www.xxx.com/pay/account/123456">点击支付</a>这个方法不错,几乎0成本,可是它有如下的缺陷(使用这种你是认真的吗?):你不知道用户是否支付成功从而无法确定订单是否完成你不知道用户输入的金额你不知道是谁向你支付,买的什么东西没有这种可爱的用户(大概吧)选项B: 直接和用户索要第三方支付的账户和密码,然后由后台进行代理购买.提出这个方案的人简直是天才,他彻底的解决了无法确认是谁支付的问题,但是有如下的不足:传输用户的帐号密码不安全由上面引发的种种不安全你不安全(重要)选项C: 使用AUTH2.0协议.用户,第三方平台和我(服务商)的想法????用户使用第三方账户登录一个新的网站,对于用户来说无非就是有如下的需求:懒的注册想利用这种第三方登入的便利性(例如:使用QQ登入百度网盘的用户免费获取2T空间)第三方平台那么对于第三方就拿腾讯来说吧,假如我有一个博客,要使用QQ登入,对于腾讯来说如何做才能保证用户的安全呢?首先确认要求接入的服务商提供者的信息资历等(必要的时候可以查水表????)然后给要求接入的服务商一个唯一凭证,标明服务商身份服务商(我)我们要做的就是将这两者进行连接起来,而具体的方式如下:正文一般来说你会得到如下的两个参数:appid 代表你的应用唯一IDappsecret 对应的密钥这个部分每家平台都不一样,具体如何获取你的APPID请参考对应平台的指南.注意:第三方平台给你的不一定是APPID,我的意思不是连名字都完全一样,有的平台给的参数多有的给的少,总之都是用于验明身份的.用户不一定第一次授权就是登录操作,这里我们以登录为例.在这个流程中服务器(我)接受到了用户想要第三方登录的请求,我们使用之前获取的APPID(不同平台叫法和参数可能不同),然后拼接为成第三方平台指定的url然后直接重定向到这个url.例如在这个例子中我们的地址可能长这个样子:www.xxx.com/oauth2.0/authorize?appid=123456&redirect=www.sss.com/login参数:appid 我们的应用对于第三方平台的唯一idredirect 用户同意授权后被重定向的地址,一般来说都是本应用的首页或者登录页面,在本例中就是www.sss.com/login这个地址.其他参数 根据第三方平会有不同的额外参数.然后将用户重定向到这个url中,此时用户会跳转到www.xxx.com.注意:重定向是一个很重要的参数,当用户同意授权后第三方服务器将会重定向到这个地址.这个时候用户被重定向到了www.xxx.com上,页面提示用户是否要向www.sss.com进行授权.如果用户同意了授权,那么第三方服务器会重定向url到我们指定的url上,在本例中就是www.sss.com/login并且带上一个code参数.在这个例子中这个url看起来是这个样子的:www.sss.com/login?code=xxxxx此时我们的www.sss.com/login接受到了一个含有code的请求,我们知道这个是一个第三方登录授权后的请求.我们再次拼接一个url(不同平台地址规则不同),但是一般来说这个请求会有如下的参数:code 用户授权后重定向带回来的codeappid 应用唯一idappsecret 应用对应的密钥在这个例子中我们请求服务器的url可能是这个样子的:www.xxx.com/oauth2/access_token?appid=xxxx&secert=xxxx&code=xxxx如果一切顺利在这个阶段我们就可以获取第三方平台响应的一个accesstoken,这个accesstoken代表着用户对于这个应用的授权.除此以外你还会获取到用户的基本信息例如用户的唯一id之类的.后续的请求用户的信息需要使用accesstoken进行请求.现在我们来完成用户的登录这个流程.利用accesstoken我们向服务器获取了用户的名字,显示在了我们的应用中.后续的资源获取就是这个模式(不同平台资源获取地址以及方式有可能稍有不同).在用户的资源请求中对于敏感的操作,都不会在前端中完成,都是代交由服务器进行资源获取.注意用户的会话持久依然是由你来做的,当用户首次授权登录后你就应该记住用户,而不是每次登录时候都进行授权.accesstoken一般都会有过期时间,使用一段时间后失效,所以在某个环节你还可以得到一个refreshtoken用于刷新accesstoken.参考&引用http://www.ruanyifeng.com/blo… https://www.cnblogs.com/flash… https://blog.csdn.net/hel_wor… https://blog.csdn.net/wang839…

December 24, 2018 · 1 min · jiezi

前端技术演进(二):前端与协议

这个来自之前做的培训,删减了一些业务相关的,参考了很多资料(参考资料列表),谢谢前辈们,么么哒 ????目前前后端的通信一般都是通过协议来完成的,这里介绍和前端开发相关的各类协议。HTTPHTTP 协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是万维网的数据通信的基础。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法,现在基本上什么类型的文件都可以传输了,比如图片、CSS、JS、数据报文等。HTTP一般基于TCP/IP通信协议来传递数据,它有如下特点:简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。支持B/S及C/S模式。HTTP使用统一资源标识符(Uniform Resource Identifiers, URI)来传输数据和建立连接。URL是一种特殊类型的URI,包含了用于查找某个资源的足够的信息。一个完整的URL一般包括以下几部分:协议 域名 端口 虚拟目录 文件名 参数 锚比如:http://test.google.com:80/test/test.html?query=admin#home请求消息Request通常一个HTTP请求消息包含如下内容:请求行、请求头、空行、消息主体。比如: GET /books/?sex=man&name=Professional HTTP/1.1 Host: www.example.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 Connection: Keep-Alive请求行:GET /books/?sex=man&name=Professional HTTP/1.1 用来说明请求类型,要访问的资源以及所使用的HTTP版本。比较常见的请求类型有GET,POST,PUT,DELETE,OPTIONS等。请求头:从第二行起为请求头部,用来说明服务器要使用的附加信息。空行:请求头部后面的空行是必须的,即使请求数据为空,也必须有空行。请求数据:也叫请求主体,可以添加任意的其他数据,这个例子的请求数据为空。带有请求数据的POST请求: POST / HTTP/1.1 Host: www.example.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 Content-Type: application/x-www-form-urlencoded Content-Length: 40 Connection: Keep-Alive sex=man&name=Professional 响应消息Response一般情况下,服务器接收并处理客户端发过来的请求后会返回一个HTTP的响应消息。通常一个HTTP请求消息包含如下内容:状态行、消息报头、空行、响应正文。比如:HTTP/1.1 200 OKDate: Fri, 22 May 2009 06:07:21 GMTContent-Type: text/html; charset=UTF-8<html> <head></head> <body> <!–body goes here–> </body></html>状态行:由HTTP协议版本号, 状态码, 状态消息 三部分组成。消息报头:用来说明客户端要使用的一些附加信息。空行:消息报头后面的空行是必须的。响应正文,服务器返回给客户端的文本信息。状态码状态码由三位数字组成,第一个数字定义了响应的类别,共分五种类别:1xx:指示信息–表示请求已接收,继续处理。2xx:成功–表示请求已被成功接收、理解、接受。3xx:重定向–要完成请求必须进行更进一步的操作。4xx:客户端错误–请求有语法错误或请求无法实现。5xx:服务器端错误–服务器未能实现合法的请求。常见的状态码有如下几种:200 OK 客户端请求成功。301 Moved Permanently 请求永久重定向。302 Moved Temporarily 请求临时重定向。304 Not Modified 文件未修改,可以直接使用缓存的文件。400 Bad Request 由于客户端请求有语法错误,不能被服务器所理解。401 Unauthorized 请求未经授权。403 Forbidden 服务器收到请求,但是拒绝提供服务。服务器通常会在响应正文中给出不提供服务的原因。404 Not Found 请求的资源不存在,例如,输入了错误的URL。500 Internal Server Error 服务器发生不可预期的错误,导致无法完成客户端的请求。503 Service Unavailable 服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常。HTTP和TCP/IP协议的关系HTTP/2HTTP2即超文本传输协议2.0版本,是HTTP协议的下一个版本。因为标准委员会不打算再发布子版本了,所以直接叫HTTP/2,而不叫HTTP/2.0。HTTP2相对于之前的HTTP协议有以下几个优点:HTTP 2采用完全二进制的格式来传输数据。同时HTTP 2对消息头采用HPACK压缩传输,最大限度地节省了传输带宽。相比于HTTP 1.x 每次请求都会携带大量冗余头信息(例如浏览器Cookie信息等),HTTP2具有很大的优势。HTTP 2使用TCP多路复用的方式来降低网络请求连接建立和关闭的开销,多个请求可以通过一个TCP连接来并发完成。HTTP2支持传输流的优先级和流量控制机制。HTTP2中每个文件传输流都有自己的传输优先级,并可以通过服务器来动态改变,服务器会保证优先级高的文件流先传输。例如在未来的浏览器端渲染中,服务器端就可以优先传输CSS文件保证页面的渲染,然后在CSS文件全部传输完成后加载JavaScript脚本文件。支持服务器端推送。服务端能够在特定条件下把资源主动推送给客户端。HTTP 1.1会让资源排队加载,如下图所示:但当我们开启了HTTP/2之后,有了TCP多路复用,个数几乎没有限制了,如下图所示:HTTP/2 将 HTTP 协议通信分解为二进制编码帧的交换,这些帧对应着特定数据流中的消息。所有这些都在一个 TCP 连接内复用。这是 HTTP/2 协议所有其他功能和性能优化的基础。目前支持HTTP2协议传输的浏览器依然很少,随着技术的发展和浏览器的更新迭代,HTTP2的时代终会到来,但我们依然不能在短时间内企图通过它来帮我们进行页面优化。HTTPSHTTPS(超文本传输安全协议 Hypertext Transfer Protocol Secure)经由HTTP进行通信,但利用SSL/TLS来加密数据包。HTTPS的主要思想是在不安全的网络上创建一安全信道。通常,HTTP 直接和 TCP 通信。当使用 SSL 时,则演变成先和 SSL 通信,再由 SSL 和 TCP 通信了。简言之,所谓 HTTPS,其实就是身披 SSL 协议这层外壳的 HTTP。HTTP的URL由“http://”起始且默认使用端口80,HTTPS的URL由“https://”起始且默认使用端口443。SSL 是独立于 HTTP 的协议,所以不光是 HTTP 协议,其他运行在应用层的 SMTP 和 Telnet 等协议均可配合 SSL(Secure Socket Layer) 协议使用。HTTP是不安全的,攻击者通过监听和中间人攻击等手段,可以获取网站帐户和敏感信息等。人们对 HTTPS 有一个普遍的错误认识,认为只有处理敏感通信的网站才需要 HTTPS。 每个未受保护的 HTTP 请求都可能暴露与用户行为和身份有关的信息。尽管访问一次未受保护的网站可能看上去无害,但一些入侵者会查看汇总的用户浏览活动,以推断他们的行为和意图,从而进行去匿名化攻击,查出匿名用户的身份。例如,员工可能在阅读未受保护的医疗文章时不经意地向其雇主泄露敏感的健康信息。公钥和私钥加密和解密同用一个密钥的方式称为共享密钥加密(Common key crypto system),也被叫做对称密钥加密。以共享密钥方式加密时必须将密钥也发给对方。可究竟怎样才能安全地转交?在互联网上转发密钥时,如果通信被监听那么密钥就可会落入攻击者之手,同时也就失去了加密的意义。SSL 采用一种叫做公开密钥加密(Public-key cryptography)的加密处理方式。公开密钥加密使用一对非对称的密钥。一把叫做私有密钥(private key),另一把叫做公开密钥(public key)。顾名思义,私有密钥不能让其他任何人知道,而公开密钥则可以随意发布,任何人都可以获得。使用公开密钥加密方式,发送密文的一方使用对方的公开密钥进行加密处理,对方收到被加密的信息后,再使用自己的私有密钥进行解密。利用这种方式,不需要发送用来解密的私有密钥,也不必担心密钥被攻击者窃听而盗走。HTTPS 采用混合加密机制:证书颁发机构公开密钥加密方式还是存在一些问题的。那就是无法证明公开密钥本身就是货真价实的公开密钥。证书颁发机构 (CA) 是一个组织,对公钥和与公共 DNS 名称之间的映射进行证实。例如,客户端如何知道特定公钥是否为 www.foobar.com 的真实公钥?按理说,无法知道。CA 证实特定密钥是特定网站的真实密钥,它使用自己的私钥来加密签名该网站的公钥。此签名在计算上是无法伪造的。浏览器(和其他客户端)维护信任锚存储库,它包含知名 CA 拥有的公钥,并且它们使用这些公钥来加密验证 CA 的签名。SSL握手流程最后使用共享密钥来进行以后的通信,详细流程:Websocket在实际的前端应用项目中,除了使用应答模式的HTTP协议进行普通网络资源文件的请求加载外,有时也需要建立客户端与服务端之间的实时连接进行通信,例如网页实时聊天的应用场景,这就必须涉及浏览器端的实时通信协议了。对于这些对实时性要求较高的应用场景,普通的HTTP协议就并不适用。虽然前端可以通过Ajax定时向服务端轮询的方式来持续获取服务端的消息,但是这种方式效率相对较低。WebSocket是浏览器端和服务器端建立实时连接的一种通信协议,可以在服务器和浏览器端建立类似Socket方式的消息通信。相对于HTTP1.1协议,WebSocket协议的优势是方便服务器和浏览器之间的双向数据实时通信。7层网络模型这里只是类似Socket方式,WebSocket 是建立在 TCP/IP 协议之上,属于应用层的协议,而 Socket 是在应用层和传输层中的一个抽象层,它是将 TCP/IP 层的复杂操作抽象成几个简单的接口来提供给应用层调用。简单回顾一下7层网络模型:简单来说,我们在传输数据时,可以只使用(传输层)TCP/IP协议,但是那样的话,如果没有应用层,便无法识别数据内容。如果想要使传输的数据有意义,则必须使用到应用层协议。应用层协议有很多,比如HTTP、FTP、TELNET等,也可以自己定义应用层协议。WEB使用HTTP协议作应用层协议,以封装HTTP文本信息,然后使用TCP/IP做传输层协议将它发到网络上。TCP/IP只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口。这个就像操作系统会提供标准的编程接口,比如win32编程接口一样,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口。Socket的出现只是使得程序员更方便地使用TCP/IP协议栈而已,是对TCP/IP协议的抽象,从而形成了我们知道的一些最基本的函数接口,比如create、listen、connect、accept、send、read和write等等。Websocket使用WebSocket 的实现分为握手,数据发送/读取,关闭连接。var ws = new WebSocket(“wss://echo.websocket.org”);ws.onopen = function(evt) { console.log(“Connection open …”); ws.send(“Hello WebSockets!”);};ws.onmessage = function(evt) { console.log( “Received Message: " + evt.data); ws.close();};ws.onclose = function(evt) { console.log(“Connection closed.”);}; 在线演示:https://html5demos.com/web-socket/DDPDDP ( Distributed Data Protocol,分布式数据协议)是一种新型的客户端与服务器端的实时通信协议,由于兼容性的原因,目前使用还不广泛。DDP使用JSON的数据格式在客户端和浏览器之间进行数据传输通信,所以对于前端开发者来说使用非常方便。有名的Meteor Web框架的双向实时数据更新机制底层使用的就是DDP,这种协议模式下客户端可向服务器端发起远程过程调用,客户端也可以订阅服务端数据,在服务端数据变化时,服务器会向客户端发起通知,触发浏览器响应的操作。//创建服务端const DDPClient = require(‘ddp’);const client = new DDPClient({ host: ’localhost’, port: 3000});//监听消息client.on(‘message’, function(data, flags){ console.log(’[DDP消息]: ‘, data);});//创建连接client.connect(function(){ client.subscribe(‘post’,[],function(){ console.log(’[post订阅消息]’); });});协议标准:https://github.com/meteor/meteor/blob/devel/packages/ddp/DDP.mdRESTfulREST (Representational State Transfer,表述性状态转化)并不是某一种具体的协议,而是定义了一种网络应用软件之间的架构关系并提出了一套与之对应的网络之间交互调用的规则。与之类似的例如早期的WebSevice,WebSevice现在基本都不用了。在REST形式的软件应用服务中,每个资源都有一个与之对应的URI地址,资源本身都是方法调用的目标,方法列表对所有资源都是一样的,而且这些方法都推荐使用HTTP协议的标准方法,例如GET、POST、PUT、DELETE等。如果一个网络应用软件的设计是按照REST定义的,我们就可以认为它使用的交互调用的方法设计遵循RESTful规范。换种方式理解,RESTful 是一种软件架构之间交互调用数据的协议风格规范,它建议以一种通用的方式来定义和管理数据交互调用接口。例如:对于书籍book的记录管理接口,有增、刪、改、查操作,于是我们定义接口:path/addBookpath/deleteBookpath/updateBookpath/getBook看上去好像没有什么问题。后来,另一个项目也有类似的接口定义,却可能叫作:path/appendBookpath/delBookpath/modifyBookpath/getBook接着有一天,项目负责人可能会说,要升级接口来满足新的需求,于是我们又添加了:path/addBook2path/deleteBook2path/updateBook2path/getBook2这样用起来是没有什么问题,但是这些随意的定义会增加数据接口维护难度和项目继续开发的成本。这时,我们或许会考虑使用文档或规范,规定一定要使用add来添加,新的接口版本号放前面 path/v2/addBook,开发的人必须严格按照文档规范去写。这样做很好,但依然不够完善,原因有以下几点:因为项目工作常常排期紧张,你可能没时间去写文档,或者后面接手的人不想去看文档。开发修改功能后很可能来不及或忘记去更新文档。无论文档写得多清楚,我们看起来效率总是很低。这时如果有一个风格更好的通用规范来定义数据交互接口,就不用这么麻烦了。所以我们完全可以利用RESTful设计的规范特性来解决上面遇到的问题。对于书籍记录操作接口的命名可以如下操作:HTTP方法URI描述POSTpath/v1/book新增书籍信息DELETEpath/v1/book删除书籍信息PUTpath/v1/book更新书籍信息GETpath/v1/book获取书籍信息使用RESTful规范来重新设计接口后,一切就变得很清晰自然,这样新的工程师接手项目时,只要他足够了解RESTful规范,几乎没有时间成本。即使他不了解RESTful规范,也可以很快地去了解,这就可以避免他去读那份看似完善其实冗长杂的文档。这里涉及到了几个设计的原则:“资源”表示一种实体,所以应该是名词,URL不应该有动词,动词应该放在HTTP协议中。按照标准,不应该在URL中包含版本号,应该放在HTTP请求头信息的Accept字段中,不过这样不够直观,所以一般的方式还是把版本号放在URL中,算是一个反模式。RESTful API 的主要设计原则就是这些,总结来说就是结合HTTP的固有方式来表征资源的状态变化描述,而不是通过动词加名词的方式来设计。Github RESTful API:https://developer.github.com/v3/GraphQLGraphQL 对 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进。GraphQL 解决的最重要的3个问题分别是:需要进行多次往返以获取所需的数据:典型的 REST API 请求多个资源时得载入多个 URL,而 GraphQL 可以通过一次请求就获取你应用所需的所有数据。客户端依赖于服务端:消除了服务器对数据内容进行硬编码的需要。我们可以把客户端与服务端分离开来,单独进行维护和改进。前后端彻底分离。糟糕的前端开发体验:使用 GraphQL,开发人员可以声明式地来表达其用户界面的数据需求,不用总是关注数据是如何获取的。RESTful APIs vs GraphQL APIs一个简单的示例:我们要做一个星球大战人物信息展示的UI界面:需要显示人物的姓名,出生年份,星球名称以及所有他们参演的电影的名称。这个 UI 的 JSON 数据可能类似于:{ “data”: { “person”: { “name”: “Darth Vader”, “birthYear”: “41.9BBY”, “planet”: { “name”: “Tatooine” }, “films”: [ { “title”: “A New Hope” }, { “title”: “The Empire Strikes Back” }, { “title”: “Return of the Jedi” }, { “title”: “Revenge of the Sith” } ] } }}如果使用 React.js ,一般会这样表示视图:// The Container Component:<PersonProfile person={data.person} ></PersonProfile>// The PersonProfile Component:Name: {person.name}Birth Year: {person.birthYear}Planet: {person.planet.name}Films: {person.films.map(film => film.title)}如果使用 RESTful API,我们可能这样请求数据:1、获取人物信息:GET - /people/{id}{ “name”: “Darth Vader”, “birthYear”: “41.9BBY”, “planetId”: 1 “filmIds”: [1, 2, 3, 6], …}2、获取星球信息:GET - /planets/13、获取所有电影信息:GET - /films/1GET - /films/2GET - /films/3GET - /films/6演示我们需要发送6个请求才能获取到所有需要的数据,每个获取数据的方法都是命令式的。每个接口返回的信息还有很多字段不是我们所需要的。为了解决这个问题,我们可能会新增加一个接口,比如:GET - /people/{id}/films但是这样就不是纯粹的RESTful API了,而且后端要额外的创建这个接口,用来满足前端的数据要求,如果增减字段或对象,后端还要添加接口或者重新编码。如果使用GraphQL,我们可以这样来查询:GET or POST - /graphql?query={…}比如参数使用:{ person(personID: 4) { name, birthYear, homeworld { name }, filmConnection { films { title } } }}演示一个请求就完成了所有数据的获取。GraphQL的灵活性也会带来一些问题,比如增加复杂度,资源耗尽攻击,N+1查询等。FB针对N+1给出了 dataloader 的方案。Github GraphQL API:https://developer.github.com/v4/在线调试:https://developer.github.com/v4/explorer/与Native交互Hybrid App是在Native App应用的基础上结合了Web App应用所形成的模式,一般称之为混合App。从技术开发上来看,相比于传统的桌面浏览器端的Web App,它具有以下几方面的特征:可用的系统网络资源更少。由于移动设备CPU、内存、网卡、网络连接多方面的限制,HybridApp的前端页面可用的系统资源远远小于桌面浏览器。就网络连接来说,大部分移动设备的使用者使用的仍是3G、4G的网络,带宽和流量均有限制,和桌面浏览器的带宽接入相比还是有着本质上的区别。支持更新的浏览器特性。目前智能设备浏览器种类相对较少,且随着硬件设备的快速更新,主流的浏览器以WebKit内核居多,支持较新的浏览器特性。不像桌面浏览器那样需要考虑较低版本Internet Explorer的兼容性问题。可实现离线应用。Hybrid的一个优势是可以通过新的浏览器特性或Native的文件读取机制进行文件级的文件缓存和离线更新。这是桌面浏览器,上较难做到的。这些离线机制常常可以用来弥补Hybrid App网络系统资源不足的缺点,让浏览器脚本更快从本地缓存中加载。较多的机型考虑。由于目前移动设备平台不统一,而且不同设备机型系统的浏览器实现仍有一定的区别,因此Hybrid App应用需要考虑不同设备机型的兼容性问题。支持与Native交互。Hybrid App的另一个特点是结合了移动端Native特性,可以在前端页面中调用客户端Native的能力,例如摄像头、定位、传感器、本地文件访问等。Web调用Native在HTML5中调用Native程序一般有几种较通用的方法:一、通过URI请求。Native应用可在移动端系统中注册一个Scheme协议的URI,这个URI可在系统的任意地方授权访问来调起一段原生方法或一个原生的界面。同样,Native 的WebView控件中的JavaScript脚本的请求也可以匹配调用这一通用的Scheme协议。例如我们通过对 window.location.href 赋值或使用iframe的方式发送一个URI的请求,这个请求可以被Native应用的系统捕获并调起Native应用注册匹配的这个Scheme协议内容。比如微信的scheme为(weixin://)。二、通过addJavascriptInterface(Android)或JavaScriptCore(iOS)注入方法到页面中调用。Android,原生Webview需要先注册可供前端调用的JS函数:// Android容器允许JS脚本,必须要webSettings.setJavaScriptEnabled(true);// Android容器设置侨连对象mWebView.addJavascriptInterface(getJSBridge(), “JSBridge”);// Android4.2版本及以上,本地方法要加上注解@JavascriptInterface,否则会找不到方法。private Object getJSBridge(){ Object insertObj = new Object(){ @JavascriptInterface public String foo(){ return “foo”; } @JavascriptInterface public String foo2(final String param){ return “foo2:” + param; } }; return insertObj; }然后H5中即可调用原生中注册的函数:// 调用方法一window.JSBridge.foo(); // 返回:‘foo’// 调用方法二window.JSBridge.foo2(’test’); // 返回:‘foo2:test’iOS,需要引入JavaScriptCore库:#import <JavaScriptCore/JavaScriptCore.h>然后原生需要注册API://webview加载完毕后设置一些js接口-(void)webViewDidFinishLoad:(UIWebView *)webView{ [self hideProgress]; [self setJSInterface];}-(void)setJSInterface{ JSContext *context =[_wv valueForKeyPath:@“documentView.webView.mainFrame.javaScriptContext”]; // 注册名为foo的api方法 context[@“foo”] = ^() { //获取参数 NSArray *args = [JSContext currentArguments]; NSString *title = [NSString stringWithFormat:@”%@",[args objectAtIndex:0]]; //做一些自己的逻辑 //返回一个值 ‘foo:’+title return [NSString stringWithFormat:@“foo:%@”, title]; }; }之后前端就可以调用了:// 调用方法,用top是确保调用到最顶级,因为iframe要用top才能拿到顶级window.top.foo(’test’); // 返回:‘foo:test’三、改写浏览器原有对象。通过修改原来浏览器的window某些方法,然后拦截固定规则的参数,然后分发给Java对应的方法去处理。这里常用的是以下四个方法:alert,可以被webview的onJsAlert监听confirm,可以被webview的onJsConfirm监听onsole.log,可以被webview的onConsoleMessage监听prompt,可以被webview的onJsPrompt监听Native调用Web需要先使用JavaScript 在HTML5页面全局中声明相对应的方法。然后Native向HTML5发起调用,Android平台一般通过loadUrl,iOS通常通过stringByEvaluatingJavaScriptFromString实现。Android调HTML5:// 异步执行JS代码,并获取返回值 mWebView.evaluateJavascript(“javascript: 方法名(‘参数,需要转为字符串’)”, new ValueCallback<String>() { @Override public void onReceiveValue(String value) { // 这里的value即为对应JS方法的返回值 }});iOS调HTML5:// 可以取得JS函数执行的返回值// 方法必须是Html页面绑定在最顶层的window上对象的// 如window.top.foo[webView stringByEvaluatingJavaScriptFromString:@“方法名(参数);”];JSBridgeJSBridge是HTML5与Native通信的桥梁,其作用是实现HTML5与Native间的双向通信。JSBridge综合了上面的技术,更多的是一种形式、一种思想,各家的实现方式也略有差异。比如微信JSSDK,就是基于WeixinJSBridge,微信浏览器中的页面,通过WeixinJSBridge调用微信提供的一些原生功能。 ...

December 14, 2018 · 3 min · jiezi

基于 Nginx 的 HTTPS 性能优化实践

摘要: 随着相关浏览器对HTTP协议的“不安全”、红色页面警告等严格措施的出台,以及向 iOS 应用的 ATS 要求和微信、支付宝小程序强制 HTTPS 需求,以及在合规方面如等级保护对传输安全性的要求都在推动 HTTPS 的发展。前言分享一个卓见云的较多客户遇到HTTPS优化案例。随着相关浏览器对HTTP协议的“不安全”、红色页面警告等严格措施的出台,以及向 iOS 应用的 ATS 要求和微信、支付宝小程序强制 HTTPS 需求,以及在合规方面如等级保护对传输安全性的要求都在推动 HTTPS 的发展。虽然 HTTPS 优化了网站访问体验(防劫持)以及让传输更加安全,但是很多网站主赶鸭子上架式的使用了 HTTPS 后往往都会遇到诸如:页面加载速度变慢、服务器负载过高以及证书过期不及时更新等问题。所以本文就来探讨一下 HTTPS 的优化实践。选型其实像 Apache Httpd、LigHttpd、Canddy 等 Web 服务软件都可以设置 HTTPS,但是在相应的扩展生态和更新率上都不如 Nginx。 Nginx 作为大型互联网网站的 Web 入口软件有着广泛的支持率,例如阿里系的 Tengine、CloudFlare 的 cloudflare-nginx、又拍云用的 OpenResty 都是基于 Nginx 而来的,Nginx 是接受过大规模访问验证的。同时大家也将自己开发的组件回馈给 Nginx 社区,让 Nginx 有着非常良好的扩展生态。 所以说 Nginx 是一款很好的 Web 服务软件,选择 Nginx 在提升性能的同时能极大的降低我们的扩展成本。新功能围绕 Web 服务已经有非常多的新功能需要我们关注并应用了,这里先罗列相关新功能。HTTP/2相比廉颇老矣的 HTTP/1.x,HTTP/2 在底层传输做了很大的改动和优化包括有:每个服务器只用一个连接,节省多次建立连接的时间,在TLS上效果尤为明显加速 TLS 交付,HTTP/2 只耗时一次 TLS 握手,通过一个连接上的多路利用实现最佳性能更安全,通过减少 TLS 的性能损失,让更多应用使用 TLS,从而让用户信息更安全在 Akamai 的 HTTP/2 DEMO中,加载300张图片,HTTP/2 的优越性极大的显现了出来,在 HTTP/1.X 需要 14.8s 的操作中,HTTP/2 仅需不到1s。HTTP/2 现在已经获得了绝大多数的现代浏览器的支持。只要我们保证 Nginx 版本大于 1.9.5 即可。当然建议保持最新的 Nginx 稳定版本以便更新相关补丁。同时 HTTP/2 在现代浏览器的支持上还需要 OpenSSL 版本大于 1.0.2。TLS 1.3和 HTTP/1.x 一样,目前受到主流支持的 TLS 协议版本是 1.1 和 1.2,分别发布于 2006年和2008年,也都已经落后于时代的需求了。在2018年8月份,IETF终于宣布TLS 1.3规范正式发布了,标准规范(Standards Track)定义在 rfc8446。TLS 1.3 相较之前版本的优化内容有:握手时间:同等情况下,TLSv1.3 比 TLSv1.2 少一个 RTT应用数据:在会话复用场景下,支持 0-RTT 发送应用数据握手消息:从 ServerHello 之后都是密文。会话复用机制:弃用了 Session ID 方式的会话复用,采用 PSK 机制的会话复用。密钥算法:TLSv1.3 只支持 PFS (即完全前向安全)的密钥交换算法,禁用 RSA 这种密钥交换算法。对称密钥算法只采用 AEAD 类型的加密算法,禁用CBC 模式的 AES、RC4 算法。密钥导出算法:TLSv1.3 使用新设计的叫做 HKDF 的算法,而 TLSv1.2 是使用PRF算法,稍后我们再来看看这两种算法的差别。总结一下就是在更安全的基础上还做到了更快,目前 TLS 1.3 的重要实现是 OpenSSL 1.1.1 开始支持了,并且 1.1.1 还是一个 LTS 版本,未来的 RHEL8、Debian10 都将其作为主要支持版本。在 Nginx 上的实现需要 Nginx 1.13+。BrotliBrotli 是由 Google 于 2015 年 9 月推出的无损压缩算法,它通过用变种的 LZ77 算法,Huffman 编码和二阶文本建模进行数据压缩,是一种压缩比很高的压缩方法。根据Google 发布的研究报告,Brotli 具有如下特点:针对常见的 Web 资源内容,Brotli 的性能要比 Gzip 好 17-25%;Brotli 压缩级别为 1 时,压缩速度是最快的,而且此时压缩率比 gzip 压缩等级为 9(最高)时还要高;在处理不同 HTML 文档时,brotli 依然提供了非常高的压缩率;在兼容 GZIP 的同时,相较 GZIP:JavaScript 上缩小 14%HTML上缩小 21%CSS上缩小 17%Brotli 的支持必须依赖 HTTPS,不过换句话说就是只有在 HTTPS 下才能实现 Brotli。ECC 证书椭圆曲线密码学(Elliptic curve cryptography,缩写为ECC),一种建立公开金钥加密的算法,基于椭圆曲线数学。椭圆曲线在密码学中的使用是在1985年由Neal Koblitz和Victor Miller分别独立提出的。内置 ECDSA 公钥的证书一般被称之为 ECC 证书,内置 RSA 公钥的证书就是 RSA 证书。由于 256 位 ECC Key 在安全性上等同于 3072 位 RSA Key,加上 ECC 运算速度更快,ECDHE 密钥交换 + ECDSA 数字签名无疑是最好的选择。由于同等安全条件下,ECC 算法所需的 Key 更短,所以 ECC 证书文件体积比 RSA 证书要小一些。ECC 证书不仅仅可以用于 HTTPS 场景当中,理论上可以代替所有 RSA 证书的应用场景,如 SSH 密钥登陆、SMTP 的 TLS 发件等。不过使用 ECC 证书有两个点需要注意:一、 并不是每一个证书类型都支持的,一般商业证书中带增强型字眼的才支持ECC证书的签发。二、 ECC证书在一些场景中可能还不被支持,因为一些产品或者软件可能还不支持 ECC。 这时候就要虚线解决问题了,例如针对部分旧操作系统和浏览器不支持ECC,可以通过ECC+RSA双证书模式来解决问题。安装下载源码综合上述我们要用到的新特性,我们整合一下需求:HTTP/2 要求 Nginx 1.9.5+,,OpenSSL 1.0.2+TLS 1.3 要求 Nginx 1.13+,OpenSSL 1.1.1+Brotli 要求 HTTPS,并在 Nginx 中添加扩展支持ECC 双证书 要求 Nginx 1.11+这里 Nginx,我个人推荐 1.15+,因为 1.14 虽然已经能支持TLS1.3了,但是一些 TLS1.3 的进阶特性还只在 1.15+ 中提供。然后我们定义一下版本号:# VersionOpenSSLVersion=‘openssl-1.1.1a’;nginxVersion=‘nginx-1.14.1’;建议去官网随时关注最新版:http://nginx.org/en/download.htmlhttps://www.openssl.org/source/https://github.com/eustas/ngx_brotli/releasesNginxcd /optwget http://nginx.org/download/$nginxVersion.tar.gztar xzf $nginxVersion.tar.gzOpenSSLcd /optwget https://www.openssl.org/source/$OpenSSLVersion.tar.gztar xzf $OpenSSLVersion.tar.gzBrotlicd /optgit clone https://github.com/eustas/ngx_brotli.gitcd ngx_brotligit submodule update –init –recursive编译cd /opt/$nginxVersion/./configure --prefix=/usr/local/nginx \ ## 编译后安装的目录位置–with-openssl=/opt/$OpenSSLVersion \ ## 指定单独编译入 OpenSSL 的源码位置–with-openssl-opt=enable-tls1_3 \ ## 开启 TLS 1.3 支持–with-http_v2_module \ ## 开启 HTTP/2 –with-http_ssl_module \ ## 开启 HTTPS 支持–with-http_gzip_static_module \ ## 开启 GZip 压缩–add-module=/opt/ngx_brotli ## 编译入 ngx_BroTli 扩展make && make install ## 编译并安装后续还有相关变量设置和设置服务、开启启动等步骤,篇幅限制就省略了,这篇文章有介绍在 Ubuntu 下的 Nginx 编译:https://www.mf8.biz/ubuntu-nginx/ 。配置接下来我们需要修改配置文件。HTTP2listen 443 ssl http2;只要在 server{} 下的lisen 443 ssl 后添加 http2 即可。而且从 1.15 开始,只要写了这一句话就不需要再写 ssl on 了,很多小伙伴可能用了 1.15+ 以后衍用原配置文件会报错,就是因为这一点。TLS 1.3ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;如果不打算继续支持 IE8,或者一些合规的要求,可以去掉TLSv1。然后我们再修改对应的加密算法,加入TLS1.3引入的新算法:ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+ECDSA+AES128:EECDH+aRSA+AES128:RSA+AES128:EECDH+ECDSA+AES256:EECDH+aRSA+AES256:RSA+AES256:EECDH+ECDSA+3DES:EECDH+aRSA+3DES:RSA+3DES:!MD5;如果不打算继续支持 IE8,可以去掉包含 3DES 的 Cipher Suite。默认情况下 Nginx 因为安全原因,没有开启 TLS 1.3 0-RTT,可以通过添加 ssl_early_data on; 指令开启 0-RTT的支持。————实验性尝试众所周知,TLS1.3 由于更新了很久,很多浏览器的旧版本依旧只支持 Draft 版本,如 23 26 28 分别在 Chrome、FirFox 上有支持,反而正式版由于草案出来很久,导致TLS1.3在浏览器上兼容性不少太好。可以使用 https://github.com/hakasenyang/openssl-patch/ 提供的 OpenSSL Patch 让 OpenSSL 1.1.1 同时支持草案23,26,28和正式版输出。 不过由于不是官方脚本,稳定性和安全性有待考量。ECC双证书双证书配置的很简单了,保证域名的证书有RSA和ECC各一份即可。 ##证书部分 ssl_certificate /usr/local/nginx/conf/ssl/www.mf8.biz-ecc.crt; #ECC证书 ssl_certificate_key /usr/local/nginx/conf/ssl/www.mf8.biz-ecc.key; #ECC密钥 ssl_certificate /usr/local/nginx/conf/ssl/www.mf8.biz.crt; #RSA证书 ssl_certificate_key /usr/local/nginx/conf/ssl/www.mf8.biz.key; #RSA密钥Brotli需要在对应配置文件中,添加下面代码即可: brotli on; brotli_comp_level 6; brotli_min_length 1k; brotli_types text/plain text/css text/xml text/javascript text/x-component application/json application/javascript application/x-javascript application/xml application/xhtml+xml application/rss+xml application/atom+xml application/x-font-ttf application/vnd.ms-fontobject image/svg+xml image/x-icon font/opentype;为了防止大家看糊涂了,放一个完整的 server{}供大家参考: server { listen 443 ssl http2; # 开启 http/2 server_name mf8.biz www.mf8.biz; #证书部分 ssl_certificate /usr/local/nginx/conf/ssl/www.mf8.biz-ecc.crt; #ECC证书 ssl_certificate_key /usr/local/nginx/conf/ssl/www.mf8.biz-ecc.key; #ECC密钥 ssl_certificate /usr/local/nginx/conf/ssl/www.mf8.biz.crt; #RSA证书 sl_certificate_key /usr/local/nginx/conf/ssl/www.mf8.biz.key; #RSA密钥 #TLS 握手优化 ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; keepalive_timeout 75s; keepalive_requests 100; #TLS 版本控制 ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers ‘TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+ECDSA+AES128:EECDH+aRSA+AES128:RSA+AES128:EECDH+ECDSA+AES256:EECDH+aRSA+AES256:RSA+AES256:EECDH+ECDSA+3DES:EECDH+aRSA+3DES:RSA+3DES:!MD5’; # 开启 1.3 o-RTT ssl_early_data on; # GZip 和 Brotli gzip on; gzip_comp_level 6; gzip_min_length 1k; gzip_types text/plain text/css text/xml text/javascript text/x-component application/json application/javascript application/x-javascript application/xml application/xhtml+xml application/rss+xml application/atom+xml application/x-font-ttf application/vnd.ms-fontobject image/svg+xml image/x-icon font/opentype; brotli on; brotli_comp_level 6; brotli_min_length 1k; brotli_types text/plain text/css text/xml text/javascript text/x-component application/json application/javascript application/x-javascript application/xml application/xhtml+xml application/rss+xml application/atom+xml application/x-font-ttf application/vnd.ms-fontobject image/svg+xml image/x-icon font/opentype; location / { root html; index index.html index.htm; } }先验证一下配置文件是否有误:nginx -t如果反馈的是:nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is oknginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful就可以重启 Nginx ,然后到对应网站中去查看效果了。验证HTTP/2通过浏览器的开发者工具,我们可以在 Network 栏目中看到 Protocol 中显示 h2 有无来判断。TLS 1.3老地方,我们可以通过浏览器的开发者工具 中的 Security 栏目看到 Connection 栏目下是否有显示 TLS 1.3ECC 双证书ECC 双证书配置了以后无非就是在旧浏览器设别上的验证了。这里用足够老的上古XP虚拟机来给大家证明一波。XP系统上:现代操作系统上的:Brotli通过浏览器的开发者工具,我们可以在 Network 栏目中,打开具体页面的头信息,看到 accept-encoding 中有 br 字眼就行。总结通过上述手段应该可以让 HTTPS 访问的体验优化不少,而且会比没做 HTTPS 的网站访问可能更快。这样的模式比较适合云服务器单机或者简单集群上搭建,如果有应用 SLB 七层代理、WAF、CDN 这样的产品可能会让我们的这些操作都白费。 我们的这几项操作都是自建的 Web 七层服务,如果有设置 SLB 七层代理、WAF、CDN 这样设置在云服务器之前就会被覆盖掉。由于 SLB 七层和CDN这样的产品会更加追求广泛的兼容性和稳定性并不会第一时间就用上上述的这些新特性(HTTP/2 是普遍有的),但是他们都配备了阿里云的 Tengine 的外部专用算法加速硬件如 Intel® QuickAssist Technology(QAT) 加速器可以显著提高SSL/TLS握手阶段性能。 所有 HTTPS 的加密解密都在 SLB 或 CDN 上完成,而不会落到ECS上,可以显著降低 ECS 的负载压力,并且提升访问体验。目前云上的网络产品中能支持四层的都是可以继续兼容我们这套设计的,例如:SLB 的四层转发(TCP UDP)、DDOS高防的四层转发。本文作者:妙正灰阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

December 5, 2018 · 3 min · jiezi

工业物联网常见的工业协议简介

[TOC]前言在目前软件事业部有很大一部分是传统IT从业人员,对于工业控制协议比较陌生,因此再做工业大数据采集时,对于各类工业协议有时容易搞不清楚,我简单把在做工业大数据采集时常见的几种工业协议整理了一下,以便搞清这些工业协议的概念和区别。OSI(Open System Interconnect)参考模型常见的工业协议按照OSI(Open System Interconnect)参考模型分到了不同层次这只是为了容易理解和区分各类协议,实际上,随着各种协议的发展,很多自身都跨越了很多层次,能够实现多层协议的功能,我们做的划分只是它最重要的功能所处的协议层。物理层RS232在串行通讯时,要求通讯双方都采用一个标准接口,使不同的设备可以方便地连接起来进行通讯。RS-232-C接口是目前最常用的 一种串行通讯接口。RS-232-C是美国电子工业协会EIA(Electronic IndustryAssociation)制定的一种串行物理接口标准。RS是英文“推荐标准”的缩写,232为标识号,C表示修改次数(“RS-232-C”中的“-C”只不过表示RS-232的版本,所以与“RS-232”简称是一样的) 。RS-232-C总线标准设有25条信号线,包括一个主通道和一个辅助通道。工业控制的RS-232口一般只使用RXD、TXD、GND三条线。通常 RS-232 接口以9个引脚 (DB-9) 或是25个引脚 (DB-25) 的型态出现,一般个人计算机上会有两组 RS-232 接口,分别称为 COM1 和 COM2。RS485随着企业信息化法发着的需要,企业在仪表选型时其中的一个必要条件就是要具有联网通信接口。最初是数据模拟信号输出简单过程量,后来仪表接口是RS232接口,这种接口可以实现点对点的通信方式,但这种方式不能实现联网功能。随后出现的RS485解决了这个问题。485通讯接口一个对通讯接口的硬件描述,它只需要两根通讯线,即可以在两个或两个以上的设备之间进行数据传输。这种数据传输的连接,是半双工的通讯方式。在某一个时刻,一个设备只能进行发送数据或接收数据。而RS232是全双工,最少3条通信线(RX,TX,GND),因为使用绝对电压表示逻辑,由于干扰,导线电阻等原因,通讯距离不远,低速时几十米也是可以的。在RS232或RS485设备联成的设备网中,如果设备数量超过2台,就必须使用RS485做通讯介质,RS485网的设备间要想相互通信息只有通过“主(Master)”设备中转才能实现,这个主设备通常是PC,而这种设备网中只允许存在一个主设备,其余全部是"从(Slave)“设备。而现场总线技术是以ISO/OSI模型为基础的,具有完整的软件支持系统,能够解决总线控制、冲突检测、链路维护等问题 。数据链路层CAN控制器局域网CAN( Controller Area Network)属于现场总线的范畴,是一种有效支持分布式控制系统的串行通信网络。是由德国博世公司在20世纪80年代专门 为汽车行业开发的一种串行通信总线。由于其高性能、高可靠性以及独特的设计而越来越受到人们的重视,被广泛应用于诸多领域。CAN协议分为二层:物理层和数据链路层。CAN的信号传输采用短帧结构,传输时间短,具有自动关闭功能,具有较强的抗干扰能力。CAN支持多主工作方式,并采用了非破坏性总线仲裁技术,通过设置优先级来避免冲突,通讯距离最远可达10KM/5Kbps/s,通讯速率最高可达40M /1Mbp/s,网络节点数实际可达110个。由于CAN总线本身的特点,其应用范围目前已不再局限于汽车行业,而向自动控制、航空航天、航海、过程工业、机械工业、纺织机械、农用机械、机器人、数控机床、医疗器械及传感器等领域发展;ProfiBusProfiBus是德国标准(DIN19245)和欧洲标准(EN50170)的现场总线标准。由PROFIBUS–DP、PROFIBUS-FMS、PROFIBUS-PA系列组成。DP用于分散外设间高速数据传输,适用于加工自动化领域。FMS适用于纺织、楼宇自动化、可编程控制器、低压开关等。PA用于过程自动化的总线类型,服从IEC1158-2标准。PROFIBUS是一种用于工厂自动化车间级监控和现场设备层数据通信与控制的现场总线技术。可实现现场设备层到车间级监控的分散式数字控制和现场通信网络,从而为实现工厂综合自动化和现场设备智能化提供了可行的解决方案。该标准广泛适用于制造业自动化、流程工业自动化和楼宇、交通电力等其他领域自动化。应用层ModBusModbus是由Modicon(现为施耐德电气公司的一个品牌)在1979年发明的,是全球第一个真正用于工业现场的总线协议。ModBus网络是一个工业通信系统,由带智能终端的可编程序控制器和计算机通过公用线路或局部专用线路连接而成。其系统结构既包括硬件、亦包括软件。它可应用于各种数据采集和过程监控。ModBus网络只有一个主机,所有通信都由他发出。网络可支持247个之多的远程从属控制器,但实际所支持的从机数要由所用通信设备决定。采用这个系统,各PC可以和中心主机交换信息而不影响各PC执行本身的控制任务。Modbus协议是应用于电子控制器上的一种通用语言。==通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信==。它已经成为一通用工业标准。有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控。此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一控制器请求访问其它设备的过程,如何回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。==Modbus是通讯协议,而RS232、RS485只能代表通讯的物理介质层和链路层。==Modbus协议支持传统的RS-232、RS-422、RS-485和以太网设备。许多工业设备,包括PLC,DCS,智能仪表等都在使用Modbus协议作为他们之间的通讯标准。软件接口OPCOPC全称是Object Linking and Embedding(OLE) for Process Control,它的出现为基于Windows的应用程序和现场过程控制应用建立了桥梁。在过去,为了存取现场设备的数据信息,每一个应用软件开发商都需要编写专用的接口函数。由于现场设备的种类繁多,且产品的不断升级,往往给用户和软件开发商带来了巨大的工作负担。通常这样也不能满足工作的实际需要,系统集成商和开发商急切需要一种具有高效性、可靠性、开放性、可互操作性的即插即用的设备驱动程序。在这种情况下,OPC标准应运而生。OPC标准以微软公司的OLE技术为基础,它的制定是通过提供一套标准的OLE/COM接口完成的,在OPC技术中使用的是OLE 2技术,OLE标准允许多台微机之间交换文档、图形等对象。总结大致上可以这样理解,RS232、RS485是硬件接口技术,CAN、ProBus等是现场总线技术,ModBus是工业控制协议,OPC是网络数据接口

November 15, 2018 · 1 min · jiezi

网络协议之 - HTTP

前言关于HTTP的知识比较繁杂,也比较零散,于是想要通过这篇文章对常用知识点进行总结,一些知识点描述是从网上搜集而来,如有侵权,可以联系我进行修改。提出问题Http的报文结构。Http request的几种类型。Http的状态码含义。Http1.1和Http1.0的区别,以及缓存原理Http长连接keep-alive。Cookie与Session的作用于原理。电脑上访问一个网页,整个过程是怎么样的:DNS、HTTP、TCP、OSPF、IP、ARP。解答1. Http的报文结构http协议的请求报文和响应报文都是由以下4部分组成:请求行请求头空行 CR + LF,回车 + 换行请求体2. Http request的几种类型请求行Request格式:【方法 URL HTTP版本】 例如: GET /csrfToken HTTP/1.1HTTP版本:目前有 HTTP/1.0、HTTP/1.1、HTTP/2.0 版本,其中 HTTP1.1 版本使用较广泛方法说明支持HTTP协议版本GET获取资源1.0 、1.1POST传输实体主体1.0、1.1PUT传输文件1.0、1.1HEAD获得报文首部1.0、1.1DELETE删除资源1.0、1.1OPTIONS询问支持的方法1.1TRACE追踪路径1.1CONNECT要求用隧道协议连接代理1.1LINK建立和资源之间的联系1.0UNLINK断开连接关系1.0Response格式:【HTTP版本 状态码 描述】 例如: HTTP/1.1 200 OK、HTTP/1.1 404 NOT FOUND 类别原因短语1xxInformational(信息性状态码)接收的请求正在处理2xxSuccess(成功状态码)请求正常处理完毕3xxRedirection(重定向状态码)需要进行附加操作以完成请求4xxClient Error(客户端错误状态码)服务器无法处理请求5xxServer Error(服务器错误状态码)服务器处理请求出错3. Http的状态码含义常用状态码200:OK,请求被正常处理204:No Content,请求被受理但没有资源可以返回,返回204响应,浏览器显示的页面不发生更新206:Partial Content,客户端进行范围请求,服务器成功执行了这部分的GET请求,响应报文中包含由Content-Range指定范围的实体内容301:Moved Permanently,永久性重定向,比如访问http://test.zhixue.com/zbptadmin,服务器会返回301,response的headers中会包含一个字段:Location: http://test.zhixue.com/zbptadmin/,浏览器会按照这个地址重新请求,并且如果用户保存了书签,浏览器会自动按照Location更新书签302:Found,临时性重定向,和301类似,但是浏览器不会更新书签303:See Other,和302类似,但303明确表示客户端应该使用GET方法获取Location资源备注:当301,302,303响应状态码返回时,几乎所有的浏览器都会把POST改成GET,并删除请求报文内的主体,之后请求会自动再次发送。301,302标准是禁止将POST方法改成GET方法的,但实际使用时浏览器厂商都会这么做。304:Not Modified,发送附带条件的请求时,(附带条件的请求是指采用GET方法的请求报文中包含If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since中任一首部),条件不满足返回304,可直接使用客户端缓存,与重定向无关307:Temporary Redirect,临时重定向,与302类似,只是强制要求使用POST方法400:Bad Request,请求报文中存在语法错误,服务器无法识别401:Unauthorized,请求需要认证403:Forbidden,请求对应的资源禁止被访问404:Not Found,服务器无法找到对应资源500:Internal Server Error,服务器内部错误503:Service Unavailable,服务器正忙常见HTTP首部字段通用首部字段(请求报文与响应报文都会使用的首部字段)Date:创建报文的时间Connection:连接的管理Cache-Control:缓存的控制Transfer-Encoding:报文主题的传输编码方式请求首部字段(请求报文会使用的首部字段)Host:请求资源所在的服务器Accept:可处理的媒体类型Accept-Charset:可接收的字符集Accept-Encoding:可接收的内容编码Accept-Language:可接收的自然语言响应首部字段(响应报文会使用的首部字段)Accept-Range:可接收的字节范围Location:让客户端重定向到的URIServer:HTTP服务器的安装信息实体首部字段(请求报文与响应报文的实体部分使用的首部字段)Allow:资源可支持的HTTP方法Content-Type:实体主类的类型Content-Encoding:实体主体适用的编码方式Content-Language:实体主体的自然语言Content-Length:实体主体的字节数Content-Range:实体主体的位置范围,一般用于发出部分请求时使用4. HTTP1.0、HTTP1.1、HTTP2.0区别HTTP1.0 和 HTTP1.1 主要区别长连接HTTP1.0需要使用keep-alive参数告知服务器要建立一个长连接,而HTTP1.1默认支持长连接HTTP是基于TCP/IP协议的,创建一个TCP连接是需要经过三次握手的,有一定的开销,如果每次通讯都要重新建立连接的话,对性能有影响。因此最好能维持一个长连接,可以用这个长连接来发送多个请求节约带宽HTTP1.1支持只发送header信息,也就是HTTP的HEAD Method,如果服务器认为客户端有权限请求服务器,则返回100,否则返回401。客户端如果接收到100,才开始把请求体body发送到服务器。这样,当服务器返回401的时候,客户端就可以不用发送请求体了,节约了带宽HTTP1.1支持分块传输,比如206状态码,由Content-Range指定传输内容,这是支持文件断点续传的基础。HOST域现在一台服务器上可以有多个虚拟主机,这些虚拟站点可以共享同一个ip和端口,HTTP1.0是没有host域的,HTTP1.1才支持这个参数HTTP1.1 和 HTTP2.0的区别多路复用HTTP2.0使用了多路复用的技术,做到同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级当然HTTP1.1也可以多建立几个TCP连接,来支持处理更多并发的请求,但是创建TCP连接本身也是有开销的TCP连接有一个预热和保护的过程,先检查数据是否传送成功,一旦成功过,则慢慢加大传输速度。因此对应瞬时并发的连接,服务器的响应就会变慢。所以最好能使用一个建立的连接,并且这个连接可以支持瞬时并发的请求HTTP/1.1,若干个请求排队串行化单线程处理,后面的请求等待前面请求的返回才能获得执行机会,一旦有某个请求超时,后续请求只能被阻塞,也就是人们常说的线头阻塞HTTP/2.0,多个请求可同时在一个连接上并行执行,某个任务耗时严重,不会影响到其他连接的正常执行数据压缩HTTP1.1不支持header数据的压缩,HTTP2.0使用HPACK算法对header的数据进行压缩,这样数据体积小了,在网络上传输就会更快服务器推送当我们对HTTP2.0的web server请求数据的时候,服务器会顺便把一些客户端需要的资源一起推送到客户端,免得客户端再次创建连接发送请求到服务器获取。这种方式非常适合加载静态资源。服务器推送的这些资源其实存在客户端的某个地方,客户端直接从本地加载这些资源就可以了,不用走网络,速度自然快很多。HTTP缓存缓存分类强缓存浏览器在加载资源时,先根据这个资源的一些http header判断它是否命中强缓存,如果命中,浏览器直接从自己的缓存中读取资源,不会发请求到服务器,此时状态码是200,但是看Size项是from memory cache或from disk cache协商缓存当强缓存没有命中时,浏览器一定会发送一个请求到服务器,通过服务器端依据资源的另外一些http header验证这个资源是否命中协商缓存,如果命中,服务器会将这个请求返回304,但是不会返回这个资源的数据,而是告诉客户端可以直接从缓存中加载这个资源,于是浏览器就又会从自己的缓存中去加载这个资源;如果没有命中,则将资源返回客户端,状态为200,浏览器同时依据response header中的相关项更新本地缓存数据from memory cache 和 from disk cache区别from memory cache 是从内存中读取缓存资源,很快,关闭浏览器后,内存中的资源就消失了from disk cache 是从磁盘中读取缓存资源,要比 from memory cache 慢,但是持久化,关闭浏览器后仍然存在哪些资源存在memory,哪些资源存在disk看了一些文章,大部分观点是说:资源在disk和memory中都会存当关闭浏览器,再打开那个页面的时候,从disk cache中获取缓存资源,同时将缓存资源存在了内存中,当再次刷新页面的时候,就从memory cache中读取,因为这样会更快一些我自己试了一些页面,再次刷新还是有的from disk cache,有的from memory cache,所以这个持保留观点还有的文章说css文件存在disk中,js等脚本存在memory中,个人认为这个不太靠谱,因为memory中的缓存在关闭浏览器就消失了,如果js只存在memory,就起不到缓存的作用了强缓存相关http headerExpiresExpires的值是服务端返回的到期时间,用GMT格式的字符串表示,如:Expires: Thu, 31 Dec 2016 23:55:55 GMT。即下一次请求时,请求时间小于服务器返回的到期时间,直接使用缓存数据。不过Expires是HTTP1.0的东西,现在浏览器默认使用HTTP1.1,所以它的作用基本忽略。另一个问题是,到期时间是由服务器生成的,但是客户端时间可能和服务器时间有偏差,这就会导致缓存命中的误差。所以HTTP1.1的版本中,使用Cache-Control替代。Cache-ControlCache-Control是最重要的规则。常见的取值有:- private:客户端可以缓存- public:客户端和代理服务器都可以缓存- max-age=xxx:缓存的内容将在xxx秒后失效,单位是秒- no-cache:需要使用协商缓存来验证缓存数据- no-store:不缓存协商缓存相关http header第1组:Last-Modified/If-Modified—SinceLast-Modified:第一次请求资源时,服务器返回的http header,告诉浏览器资源的最后修改时间,为GMT格式,如Last-Modified: Thu, 24 Jan 2017 23:55:55 GMTIf-Modified-Since:再次请求服务器资源时,浏览器设置在请求header中,值 为该资源第一次请求时服务器设置的Last-Modified`值,如If-Modified-Since: Thu, 24 Jan 2017 23:55:55 GMT,服务器收到请求后发现request header中有If-Modified-Since,则与被请求资源的最后修改时间进行比对。若资源的最后修改时间大于If-Modified-Since,说明资源又被改动过,则返回资源内容,状态码200,同时浏览器依据相应response header更新缓存资源;若资源的最后修改时间小于或等于If-Modified-Since,说明资源无新修改,则返回状态码304,但是不返回资源,告知浏览器继续使用所保存的cache第2组:Etag/If-None-MatchEtag:服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器确定),如Etag: W/“5886c231-8d9"If-None-Match:再次请求服务器时,通过此字段告知服务器该资源的唯一标识,如If-None-Match: W/“5886c231-8d9”,服务器收到请求后发现request header中有If-None-Match,则与被请求资源的唯一标识进行比对,若不同,说明资源又被改动过,则返回资源内容,状态码200,同时浏览器依据相应response header更新缓存资源;若相同,则说明资源无更改,返回304,告知浏览器继续使用所保存的缓存资源为什么要有Etag?Last-Modified颗粒度是秒,只能记录秒级的修改,比如1s内修改了N次,If-Modified-Since就无法判断了,所以要引入Etag。总结先执行强缓存策略,服务器通知浏览器一个缓存有效时间,在有效时间内,下次请求时直接使用缓存,不发起http请求,缓存从from memory cache或from disk cache中读取,若超过了有效时间,则执行协商缓存策略对于协商缓存,将缓存信息中的Etag和Last-Modified的值通过If-None-Match和If-Modified-Since发送给服务器,由服务器进行校验,若资源无更改,返回304,浏览器继续使用缓存,若资源被更改,则返回资源,状态码200,同时浏览器更新缓存流程图浏览器第一次请求:浏览器第二次请求:5. Http长连接keep-alive三个概念短连接所谓短连接,就是每次请求一个资源就建立连接,请求完成后立马关闭。每次请求都经过“创建TCP连接 -> 请求资源 -> 响应资源 -> 释放连接”。长连接所谓长连接(persistent connection),就是只建立一次TCP连接,多次HTTP请求都复用该连接。并行连接所谓并行连接(multiple connection),其实就是并发的短连接。keep-alive在HTTP/1.0里,为了实现client到web-server能支持长连接,必须在HTTP请求头里显式指定Connection: keep-alive在HTTP/1.1里,就默认开启了keep-alive,要关闭keep-alive必须在HTTP请求头里显式指定Connection: close现在大多数浏览器都默认是使用HTTP/1.1,所以keep-alive都是默认打开的。一旦client和server达成协议,那么长连接就建立好了。keepalive_timeoutHttpd守护进程,一般都提供了keep-alive timeout时间设置参数。比如nginx的keepalive_timeout,和Apache的KeepAliveTimeout。这个keepalive_timout时间值意味着:一个http产生的tcp连接在传送完最后一个响应后,还需要hold住keepalive_timeout秒后,才开始关闭这个连接。Nginx配置中的keepalive_timeout默认为75s,6. cookie与Session这个重点在于理解,这里就不赘述了。7. 网页经历了什么这个东西很多,后面会专门写一篇文章来进行说明。参考文章:HTTP1.0、HTTP1.1 和 HTTP2.0 的区别彻底弄懂HTTP缓存机制及原理What is the difference between memory cache and disk cache in Chrome?理解HTTP之keep-alive ...

October 19, 2018 · 1 min · jiezi