深入认识 HTTP 的特性

1. HTTP 协议中的编码和解码

1.1 字符集与解码

字库表(character repertoire):相当于一个 所有 可读或者可显示字符的数据库(可读的字符不一定能够直观的显示出来,如回车)。其决定了编码字符集能够展示的字符的范围。每一种编码字符集,应该都对应着一个字库表。例如 ASCII 字符集,对应的字库表就是由换行、回车等控制字符,和数字、大小写字母、英文标点符号等 128 个字符组成的。且这 128 个字符,是按照一定顺序来排列的。这里需要注意,字库表本身只包含按照顺序排序的字符,而不包含标记字符位置的序号。

编码字符集(coded character set):是字库表中所有字符以及对应的编码的集合(这里的 “编码”,是名词)。每一个编码(Code Point),都是一个二进制代码(因为计算机的底层就是基于二进制的),且都对应着字库表中的一个字符(就类似于摩斯电码,A 对应的代码为 ·-)。而该编码,一般取值为字符在字库表中的位置序号。

字符编码:(这里的 “编码”,是动词)是一种映射规则,通过这种规则,就可以把存储二进制的数据转换成对应的字符,或者把字符转换为用于存储的二进制数据。而不是直接将编码字符集中的编码进行存储,不依照规则,则可能出现乱码。

流程:二进制数通过某种编码方式,转化成字符集对应的地址,然后在字库表找到对应的字符,并展示给用户。

1.2 常见编码规范介绍

UTF8 编码方式与 Unicode 编码规范

UTF-8是一种变长字节编码方式,是 Unicode 的一种实现方式。对于某一个字符的UTF-8编码,如果只有一个字节则其最高二进制位为0;如果是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了其编码的位数,其余各字节均以10开头。UTF-8最多可用到6个字节。

1字节 0xxxxxxx
2字节 110xxxxx 10xxxxxx
3字节 1110xxxx 10xxxxxx 10xxxxxx
4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

因此UTF-8中可以用来表示字符编码的实际位数最多有31位,即上表中x所表示的位。除去那些控制位(每字节开头的10等),这些x表示的位与UNICODE编码是一一对应的,位高低顺序也相同。

实际将UNICODE转换为UTF-8编码时应先去除高位0,然后根据所剩编码的位数决定所需最小的UTF-8编码位数。

因此那些基本ASCII字符集中的字符(UNICODE兼容ASCII)只需要一个字节的UTF-8编码(7个二进制位)便可以表示。

1.3 乱码的由来

解码

由二进制转化为对应的字符,可以知道,只有一种解法才能解出正确答案,其他的解法会产生乱码。

编码

解码后的字符编码成二进制 ,字库表里不包含目标字符,也会产生乱码。比如用 ISO8859 编码后的汉字用 ISO8859 进行解码,因为 ISO8859 字库表里边没有汉字,自然解不出来。

1.4 URL 的编码和解码

  • URL 是采用 ASCII 字符集进行编码的,所以如果 URL 中含有非 ASCII 字符集中的字符,要对其进行编码。
  • URL 中一些保留字符,如”&“表示参数分隔符,如果想要在 URL 中使用这些保留字,那就需要编码。
  • ”%编码“规范:对 URL 中属于 ASCII 字符集的非保留字不做编码;对 URL 中的保留字需要取其 ASCII 内码,然后加上”%“前缀将该字符进行编码;对于 URL 中的非 ASCII 字符需要取其 Unicode 内码,然后加上”%“前缀将该字符进行编码。

2. HTTP 协议之基本认证

2.1 身份认证

  • 密码
  • 动态令牌
  • 数字证书
  • 生物认证
  • IC 卡等

2.2 常见认证方式

  • BASIC 认证(基本认证)
  • DIGEST 认证(摘要认证)
  • SSL 客户端认证
  • FormBase 认证(基于表单认证)

2.2.1 BASIC 认证

上面的流程一看,就挺麻烦。而且,虽然采用 Base64 进行编码,但是并不是加密加密处理,不需要额外信息就可以解码,如果非加密通信被窃听的话,用户十分容易被盗。

2.2.2 DIGEST 认证

为弥补 BASIC 认证存在的弱点,从 HTTP/1.1 起就有了 DIGEST 认证。

DIGEST 认证同样使用质询/响应的范式,但不会像 BASIC 认证那样直接发送明文密码。

所谓质询响应方式是指,一开始一方会先发送认证要求给另一方, 接着使用从另一方那接收到的质询码计算生成响应码。最后将响应码返 回给对方进行认证的方式。

  1. 请求需认证的资源时,服务器会随着状态码 401 Authorization Required, 返回带 WWW - Authenticate 首部字段的响应。 该字段内包含质问响应方式认证所需的临时质询码(随机 数,nonce)。首部字段 WWW - Authenticate 内必须包含 realm 和 nonce 这两个字段的信息。客户端就是依靠向服务器回送这两个 值进行认证的。

    nonce 是一种每次随返回的 401 响应生成的任意随机字符 串。该字符串通常推荐由 Base64 编码的十六进制数的组 成形式,但实际内容依赖服务器的具体实现。

  2. 接收到 401 状态码的客户端,返回的响应中包含 DIGEST 认证必须的首部字段 Authorization 信息。

    首 部 字 段 Authorization 内 必 须 包 含 username、realm、 nonce、uri 和 response 的字段信息。 其中,realm 和 nonce 就是之前从服务器接收到的响应中的字段。

    username 是 realm 限定范围内可进行认证的用户名。

    uri(digest - uri)即 Request - URI 的值,但考虑到经代理转 发后 Request - URI 的值可能被修改,因此事先会复制一份 副本保存在 uri 内。

    response 也可叫做 Request - Digest,存放经过 MD5 运算后 的密码字符串,形成响应码。

  3. 接收到包含首部字段 Authorization 请求的服务器,会确认 认证信息的正确性。认证通过后则返回包含 Request - URI 资源的响应。

    response 传给服务器后,服务器进行认证,即根据用户名查找到用户的密码,然后用和客户端同样的方式计算出 request-digest(response)。然后两个 response 相比较,如果一致,则验证成功。成功后返回结果,在首部字段 Authentication - Info 写入一些认证 成功的相关信息。

上面的算法只是想说,密码和随机数混杂到里边了,大大提高了密码的安全。

DIGEST 认证提供了高于 BASIC 认证的安全等级,但是和 HTTPS 的客户端认证相比仍旧很弱。DIGEST 认证提供防 止密码被窃听的保护机制,但并不存在防止用户伪装的保护机制。

DIGEST 认证和 BASIC 认证一样,使用上不那么便捷灵活,且仍达不到多数 Web 网站对高度安全等级的追求标准。因此它的适用范围也有所受限。

2.2.3 SSL 客户端认证

从使用用户 ID 和密码的认证方式方面来讲,只要二者的内容正确,即可认证是本人的行为。但如果用户 ID 和密码被盗,就很有可能被第 三者冒充。利用 SSL 客户端认证则可以避免该情况的发生。

SSL 客户端认证是借由 HTTPS 的客户端证书完成认证的方式。 凭借客户端证书认证,服务器可确认访问是否来自已登录的客户端。

步骤

为达到 SSL 客户端认证的目的,需要事先将客户端证书分发给客户端,且客户端必须安装此证书。

  1. 接收到需要认证资源的请求, 服务器会发送 Certificate Request 报文,要求客户端提供客户端证书。
  2. 用户选择将发送的客户端证书后,客户端会把客户端证书 信息以 Client Certificate 报文方式发送给服务器。
  3. 服务器验证客户端证书验证通过后方可领取证书内客户端的公开密钥,然后开始 HTTPS 加密通信。

虽然安全了,但是有一定的成本问题,需要从认证机构购买客户端证书,以及服务器运营者为保证自己搭建的认证机构安全运营也会产生费用。

2.2.4 基于表单认证

由于使用上的便利性及安全性问题,HTTP 协议标准提供的 BASIC 认证和 DIGEST 认证几乎不怎么使用。另外,SSL 客户端认证虽然具有高度的安全等级,但因为导入及维持费用等问题,还尚未普及。

基于表单的认证方法并不是在 HTTP 协议中定义的。

使用由 Web 应用程序各自实现基于表单的认证方式。

基于表单认证的标准规范尚未有定论,一般会使用 Cookie 来管理 Session(会话)。

鉴于 HTTP 是无状态协议,之前已认证成功的用户状态无法通过 协议层面保存下来。即,无法实现状态管理,因此即使当该用户下一次继续访问,也无法区分他与其他的用户。 于是我们会使用 Cookie 来管理 Session,以弥补 HTTP 协议中不存在的状态管理功能。

  1. 客户端把用户 ID 和密码等登录信息放入报文的实体部分,通常是以 POST 方法把请求发送给服务器。而这时,会使用 HTTPS 通信来进行 HTML 表单画面的显示和用户输入 数据的发送。

  2. 服务器会发放用以识别用户的 Session ID。通过验证从客户端发送过来的登录信息进行身份认证,然后把用户的认证状态与 Session ID 绑定后记录在服务器端。向客户端返回响应时, 会在首部字段 Set - Cookie 内写入 Session ID。

    但是这就会造成衣蛾问题,如果 Session ID 被盗,对方就可以伪装成你的身份进行恶意操作。

    因此为了防止 Session ID 被盗走或者被猜出,Session 应使用难以推测的字符串,且服务端对 Session ID 进行有效期的管理,保证其安全性。同时为减轻跨站脚本攻击(XSS)造成的损失(大多数 XSS 攻击都是针对 Cookie 的盗窃),建议实现在 Cookie 内加上 httponly 属性(客户端脚本将无法访问 cookie)。

  3. 客户端接收到从服务器端发来的 Session ID 后,会将其作为 Cookie 保存在本地。

    下次向服务器发送请求时,浏览器会自动发送 Cookie,所以 Session ID 也随之发送到服务器。 服务器端可通过验证接收到的 Session ID 识别用户和其认证状态。

密码加盐

虽然基于表单认证,数据库里可以存储密码通过哈希加密后的哈希值,但是仍然存在着一定的风险。使用暴力破解(一个个试),查表法等。暴力破解一般天荒地老,查表法,比如使用彩虹表,表里存储了大量密码加密后的哈希值,依次和数据库里获得的哈希值进行比对,匹配成功便成功破解(可以看出,相比于暴力破解,是空间换时间)。

服务器端一般使用密码加盐的办法,先生成一个足够长的随机数(盐值),然后混进密码后进行哈希函数进行加密(如 SHA256)。比较计算结果和数据库存储的哈希值,如果相同就代表密码正确。

对于每个用户的每个密码,盐值都应该是独一无二的。每当有新用户注册或者修改密码,都应该使用新的盐值进行加密。并且这个盐值也应该足够长,使得有足够多的盐值以供加密。一个好的标准的是:盐值至少和哈希函数的输出一样长;盐值应该被储存和密码哈希一起储存在账户数据表中。

当两个用户使用了同一个密码时,由于随机生成的 salt 值不同,对应的散列值也将是不同的。这样一来,很大程度上减少了密码特征,攻击者也 就很难利用自己手中的密码特征库进行破解。

3. HTTP 的长连接和短连接

  • HTTP 协议是基于请求/响应模式的,因此只要服务端给了响应,本次 HTTP 请求就结束了。
  • HTTP 的长连接和短连接本质上是 TCP 长连接和短连接。
  • HTTP/1.0 中,默认使用的是短连接。也就是说,浏览器和服务器每进行一次 HTTP 操作,就建立一次连接,结束就中断。
  • HTTP/1.1 起,默认使用长连接,用以保持连接特性。响应头里携带 Connection: keep-alive。可以设置长连接的连接时间。

可以看出,短连接管理较为简单,但是用户请求过于频繁的话,多出来的建立连接和关闭连接,会浪费时间和浪费带宽,用户体验较差。

长连接就有另外一个问题,长时间占用连接没有释放的话,会给服务端带来压力,所以服务端需要采取策略,例如关闭长时间没有数据传输的连接,避免恶意连接。限制每个客户端的最大连接数等。

问:我们为什么需要持久连接?它的特点又是什么?

HTTP协议的初始版本中,每进行一次HTTP通信就要断开一次TCP连接。以当年的通信情况来说,因为都是些容量很小的文本传输,所以即使这样也没有多大问题。可随着 HTTP 的 普及,文档中包含大量图片的情况多了起来。比如,使用浏览器浏览一个包含多张图片的 HTML 页面时,在发送请求访问 HTML 页面资源的同时,也会请求该 HTML 页面里包含的其他资源。因此,每次的请求都会造成无谓的 TCP 连接建立和断开,增加通信量的开销。

为解决上述 TCP 连接的问题,HTTP/1.1 和一部分的 HTTP/1.0 想出了持久连接(HTTP Persistent Connections,也称为 HTTP keep-alive 或 HTTP connection reuse)的方法。持久连接的特点是,只要任意一端没有明确提出断开连接,则保持TCP连接状态。

持久连接的好处在于减少了 TCP 连接的重复建立和断开所造成的额外开销,减轻了服务器端的负载。另外, 减少开销的那部分时间,使 HTTP 请求和响应能够更早地结束,这样 Web 页面的显示速度也就相应提高了。

4. HTTP 中介之代理

使用代理服务器的理由有:利用缓存技术(稍后讲解)减少网络带宽的流量,组织内部针对特定网站的访问控制,以获取访问日志为主要目的,等等。

代理有多种使用方法,按两种基准分类。一种是是否使用缓存,另一种是是否会修改报文。

  1. 缓存代理

    代理转发响应时,缓存代理(Caching Proxy)会预先将资源的副本(缓存)保存在代理服务器上。

    当代理再次接收到对相同资源的请求时,就可以不从源服务器那里获取资源,而是将之前缓存的资源作为响应返回。

  2. 透明代理

    转发请求或响应时,不对报文做任何加工的代理类型被称为透明代理(Transparent Proxy)。反之,对报文内容进行加工的代理被称为 非透明代理。

代理的作用

  • 抓包:拦截服务器

  • FQ

  • 匿名访问

  • 过滤器

    通过代理服务器进行分析和拦截

5. HTTP 中介之网关

网关的工作机制和代理十分相似。而网关能使通信线路上的服务器提供非 HTTP 协议服务。

  • 网关可以作为某种翻译器使用,它抽象出了一种能够到达资源的方法。网关是资源和应用程序之间的粘合剂。
  • 网关扮演的是”协议转换器“的角色。

  • Web 网关在一侧使用 HTTP 协议,在另一侧使用另一种协议。

    客户端协议 / 服务端协议

  • (HTTP/) 服务器端网关:通过 HTTP 协议与客户端对话,通过其他协议与服务器通信。

  • (/HTTP) 客户端网关:通过其他协议与客户端对话,通过 HTTP 协议与服务器通信。

常见的网关类型

  1. (HTTP/*) 服务器端 Web 网关
  2. (HTTP/HTTPS) 服务器端安全网关
  3. (HTTPS/HTTP) 客户端安全加速器网关
  4. 资源网关

利用网关能提高通信的安全性,因为可以在客户端与网关之间的通信线路上加密以确保连接的安全。 比如, 网关可以连接数据库, 使用 SQL 语句查询数据。另外, 在 Web 购物网站上进行信用卡结算时, 网关可以和信用卡结算系统联动。

5. HTTP 缓存

缓存是指代理服务器或客户端本地磁盘内保存的资源副本。利用缓存可减少对源服务器的访问,因此也就节省了通信流量和通信时间。

缓存的内容针对 CSS,JS,图片等更新不大的静态文件。

缓存服务器是代理服务器的一种,并归类在缓存代理类型中。换句话说,当代理转发从服务器返回的响应时,代理服务器将会保存一份资源的副本。

5.2 HTTP 缓存头部字段

5.3 HTTP 缓存工作方式

  • 场景一:让服务器与浏览器约定一个文件的过期时间 Expires。对比当前时间是否超过 Expires,如果没超过时间不发出请求,直接使用本地缓存,否则访问服务器。Cache-control 类似,但是如果 Expires 和 Cache-Control 同时存在的话,Expires 会被 Cache-Control 的 max-age 覆盖。这就是强制缓存。
  • 场景二:让服务器与浏览器在约定文件过期时间的基础上,再加一个文件最新修改时间的对比 —— Last-Modified 与 if-Modified-Since。如果强制缓存过期,客户端发送请求的时候请求头携带 if-Modified-Since 和服务器的 Last-Modified 进行对比。如果两者比对相同,则说明文件没修改,直接用本地的缓存,不相等的话,服务器拿最新的版本给客户端。Last-Modified 只能精确到秒,秒内的多次更新无法感知。
  • 场景三:让服务器与浏览器在过期时间 Expires + Last-Modified 的基础上,增加一个文件内容唯一对比标记—— Etag 与 If-None-Match。Expires 不稳定,再加入一个 Cache-Control 的 max-age 来加以代替。Etag 是文件内容的唯一标识,优先级比 Last-Modified 高,毕竟精确度更高。上面两种场景,因为通过访问服务器来判断是否使用缓存,因此称为协商缓存。

上面的方案都存在缺陷:在强制缓存未失效的情况下,客户端无法主动感知服务端的文件变化。

缓存改进方案

  • MD5/hash 缓存:解决强制缓存死板的问题

    通过不缓存 HTML,为静态文件添加 MD5 或者 hash 表示,解决浏览器无法跳过缓存过期时间主动感知文件变化的问题。

    因为强制缓存和协商缓存的前提建立在两者文件路径完全相同。如果文件名称变化了,浏览器会直接访问新文件。

  • CDN 缓存

    CDN 是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。

CDN 缓存工作方式

使用 CDN 后,当我们使用域名访问某一站点,DNS 便不会返回一个 IP 地址,而是一个 CNAME 别名记录,指向 CDN 的全局负载均衡。

CDN 的全局负载均衡系统进行智能调度:

  • 看用户的 IP 地址,查表得知地理位置,找相对最近的边缘节点
  • 看用户所在的运营商网络,找相同网络的边缘节点
  • 检查边缘节点的负载情况,找负载较轻的节点
  • 其他,比如节点的“健康状况”、服务能力、带宽、响应时间等

结合上面的因素,得到最合适的边缘节点,然后把这个节点返回给用户,用户就能够就近访问 CDN 的缓存代理。

CDN 会缓存最常用的那些资源,也是遵守强制缓存和协商缓存。如果 CDN 的缓存文件过期了,也是得找源服务器去要。但 CDN 可以手动更新。

且缓存系统也可以划分出层次,分成一级缓存节点和二级缓存节点。一级缓存配置高一些,直连源站,二级缓存配置低一些,直连用户。

回源的时候二级缓存只找一级缓存,一级缓存没有才回源站,可以有效地减少真正的回源。

浏览器操作对 HTTP 缓存的影响

6. HTTP 内容协商机制

内容协商机制是指客户端和服务器端就响应的资源内容进行交涉,然后提供给客户端最为适合的资源。内容协商会以响应资源的语言、字符集、编码方式等作为判断的基准。包含在请求报文中的某些首部字段(如下)就是判断的基准。

应用:同一个 Web 网站有可能存在着多份相同内容的页面。 比如英语版和中文版的 Web 页面,它们内容上虽相同,但使用的语言却不同。

当浏览器的默认语言为英语或中文,访问相同 URI 的 Web 页面时, 则会显示对应的英语版或中文版的 Web 页面。 这样的机制称为内容协商(Content Negotiation)。

内容协商方式

  • 客户端驱动

    客户端发起请求,服务器发送可选项列表,客户端做出选择后再发送第二次请求。缺点是得发两次请求。

  • 服务器驱动

    由服务器端进行内容协商。以请求的首部字段为参考,在服务器端自动处理。但对用户来说,以浏览器发送的信息作为判定的依据, 并不一定能筛选出最优内容。

  • 透明协商

    某个中间设备(通常是缓存代理)代表客户端进行协商。缺点是,没有提供相关的 HTTP 规范。

服务器驱动内容协商请求首部集

  • Accept 告知服务器发送何种媒体类型
  • Accept-Charset 告知服务器发送何种字符集
  • Accept-Encoding 告知服务器采用何种编码
  • Accept-Language 告知服务器发送何种语言

服务器响应与上面一一对应:

  • Content-Type
  • Content-Language
  • Content-Type
  • Content-Encoding

服务器驱动内容协商-近似匹配

用户最愿意接受荷兰语,如果没有就英语,但是不接受法语和土耳其语。

但是万一服务器里没有荷兰语和英语,那服务器就得进行猜测。一般来讲,服务器端会设有默认值。

7. 断点续传和多线程下载

7.1 断点续传

HTTP 通过在 Header 里两个参数实现的,客户端发请求时对应的是 Range,服务器端响应时对应的是 Content-Range。

如果续传成功返回 206,如果文件有变动就返回 200 并返回文件新内容

完整的断点续传过程

7.2 多线程下载

多线程是主动的分片下载,但原理和断点续传是一样的。

03.深入认识 HTTP 的特性相关推荐

  1. 涡轮机叶片matlab强度分析论文,燃气轮机涡轮叶片受力特性计算及分析.doc

    毕业设计(论文) 题目:燃气轮机涡轮叶片受力特性计算及分析 学 生 姓 名: 张 海 诺 学 号: 班 级: 专 业: 指 导 教 师: 2015年 03月 燃气轮机涡轮叶片受力特性计算及分析 学 生 ...

  2. Sklearn中的CV与KFold详解

    关于交叉验证,我在之前的文章中已经进行了简单的介绍,而现在我们则通过几个更加详尽的例子.详细的介绍 CV %matplotlib inline import numpy as np from skle ...

  3. 终于有人把「同侪效应」讲明白了

    导读:本文将从用户群体效应的角度来分析场景化设计,用"同侪效应"的概念系统阐释群体用户对个体用户的影响. 作者:朱军华 来源:大数据DT(ID:hzdashuju) 在场景化设计时 ...

  4. Python 基础(二)[列表,字典,文件操作]

    本章内容: 列表 & 元组操作 字符串操作 字典操作 集合操作 文件操作 字符编码与转码  Python  语言从未如此性感! 列表 Python中最基本的数据结构 Python有6个序列的内 ...

  5. 现代永磁同步电机控制原理及matlab仿真_永磁同步电机是什么?

    我们从特斯拉汽车开始说起,特斯拉这个名字是为了纪念尼古拉·特斯拉 现代交流电力系统的建立者,电机工程学的先驱.人们当前的现代化生活很大一部分要归功于这位神一样的男人. 特斯拉的车标灵感来源于电机结构的 ...

  6. for each 用法

    package victory;import java.util.List;public class Foreach1 {public static void main(String[] args) ...

  7. 跨境边民带货溯源方案分享

    国内跨境电商的飞速发展,为我国人民生活带来了许多便利.可是在行业的背后,往往隐藏着假货泛滥等多种问题,令人们感到十分担忧.为了能够打消大众质疑,国内企业纷纷加码布局对跨境商品的溯源和检查手段. 跨境电 ...

  8. 跨境边民带货溯源方案-助力口岸海关边民带货,创新发展口岸经济

    国内跨境电商的飞速发展,为我国人民生活带来了许多便利.可是在行业的背后,往往隐藏着假货泛滥等多种问题,令人们感到十分担忧.为了能够打消大众质疑,国内企业纷纷加码布局对跨境商品的溯源和检查手段.跨境电商 ...

  9. 【switch case简单案例】

    switch case语句 switch case格式: switch(表达式) { case 常量表达式1:语句1;break; case 常量表达式2:语句2;break; - case 常量表达 ...

最新文章

  1. hdu-----(4514)湫湫系列故事——设计风景线(树形DP+并查集)
  2. salt.states.file试用
  3. VRRP——虚拟路由器冗余协议
  4. WPF:Graphics绘图--Shapes形状
  5. SimpleAdapter类使用方法
  6. React开发(124):ant design学习指南之form中的validateFields
  7. 解决Mac打开matlab编码问题
  8. 【编译原理笔记16】代码优化:流图,常用代码优化方法, 基本块的优化
  9. @NotEmpty@NotNull和@NotBlank的区别
  10. Eclipse用法和技巧二十:一个快速打印技巧
  11. AUTOCAD参数约束功能
  12. SEO人员,你真的要做一个采集侠吗?
  13. arping指令linux,arping
  14. 企业微信双开及三开的方法
  15. 未转变者怎么调服务器难度,未转变者服务器怎么设置出生点 | 手游网游页游攻略大全...
  16. 2020牛客寒假算法基础集训营4.G——音乐鉴赏【概率】
  17. 存储组件之MFS详解
  18. php jquery 时间轴,jquery时间轴
  19. 人这一辈子,都在为选择买单
  20. Real-Time Rendering读书笔记——01

热门文章

  1. 本科专业、学科、专业学位
  2. WMS系统解决方案,多系统无缝集成,解决信息孤岛
  3. 父镜像、子镜像、AUFS、UFS之间的关系、基础镜像
  4. 学习PS好处都有哪些?
  5. 神经网络相关的绘图工具
  6. Go_Channel详解
  7. 路遥短篇小说之《匆匆过客》
  8. 基于Springboot的宠物医院管理系统-JAVA【毕业设计、论文、源码、开题报告】
  9. matlab中方差直方图,如何在MATLAB中标准化直方图?
  10. 四自由度机械手c语言编程设计,四自由度机械手的机械结构原理毕业设计毕业论文...