30

走在前端的大道上

本篇将自己读过的相关 http/https 方法 文章中,对自己有启发的章节片段总结在这(会对原文进行删改),会不断丰富提炼总结更新。

Web 基础

  • HTTP(HyperText Transfer Protocol,超文本传输协议)。
  • WWW(World Wide Web)的三种技术:HTML、HTTP、URL。
  • RFC(Request for Comments,征求修正意见书),互联网的设计文档。

URL

  • URI(Uniform Resource Indentifier,统一资源标识符)
  • URL(Uniform Resource Locator,统一资源定位符)
  • URN(Uniform Resource Name,统一资源名称),例如 urn:isbn:0-486-27557-4 。

URI 包含 URL 和 URN,目前 WEB 只有 URL 比较流行,所以见到的基本都是 URL。

clipboard.png

HTTP

超文本传输​​协议(HTTP)是用于传输诸如HTML的超媒体文档的应用层协议。它被设计用于Web浏览器和Web服务器之间的通信,但它也可以用于其他目的。 HTTP遵循经典的客户端-服务端模型,客户端打开一个连接以发出请求,然后等待它收到服务器端响应。 HTTP是无状态协议,意味着服务器不会在两个请求之间保留任何数据(状态)。

HTTP是明文传输的,也就意味着,介于发送端、接收端中间的任意节点都可以知道你们传输的内容是什么。这些节点可能是路由器、代理等。

举个最常见的例子,用户登陆。用户输入账号,密码,采用HTTP的话,只要在代理服务器上做点手脚就可以拿到你的密码了。

用户登陆 --> 代理服务器(做手脚)--> 实际授权服务器

在发送端对密码进行加密?没用的,虽然别人不知道你原始密码是多少 ,但能够拿到加密后的账号密码,照样能登陆。

HTTP是应用层协议,位于HTTP协议之下是传输协议TCP。TCP负责传输,HTTP则定义了数据如何进行包装。

1.HTTP协议的主要特点

简单快速、灵活、无连接、无状态

2.HTTP报文的组成部分

请求报文 响应报文
请求行 请求头 空行 请求体 状态行 响应头 空行 响应体

请求报文

clipboard.png

响应报文

clipboard.png

3.HTTP方法

GET ----> 获取资源
POST ----> 传输资源
PUT ----> 更新资源
DELETE ----> 删除资源
HEAD ----> 获取报文首部

4.POST 和 GET 的区别

  1. GET在游览器回退是无害的,而POST会再次提交请求
  2. GET请求会被游览器主动缓存,而POST不会,除非手动设置
  3. GET请求参数会被完整的保留在游览器历史记录里,而POST中的参数不会被保留
  4. GET产生的URL地址可以被收藏,而POST不可以
  5. GET参数通过URL传递,而POST放在Request body
  6. GET请求只能进行URL编码,而POST支持多种编码方式
  7. GET请求在URL中传递的参数是有长度限制的,而POST没有限制
  8. GET请求会把参数直接暴露在URL上,相比POST更安全
  9. 对参数的数据类型,GET只接受ASCII字符,而POST没有限制

clipboard.png

5.HTTP状态码

状态 信息
1xx 指示信息 - 表示请求已接受,继续处理
2xx 成功 - 表示请求已被成功接收
3xx 重定向 - 要完成请求必须进行进一步的操作
4xx 客户端错误 - 请求有语法错误或请求无法实现
5xx 服务器错误 - 服务器未能实现合法的请求

6.什么是持久化链接

clipboard.png

7.什么是管线化

clipboard.png

HTTPS科普扫盲帖
notes/HTTP

HTTPS

HTTPS相对于HTTP有哪些不同呢?其实就是在HTTP跟TCP中间加多了一层加密层TLS/SSL。

神马是TLS/SSL?

通俗的讲,TLS、SSL其实是类似的东西,SSL是个加密套件,负责对HTTP的数据进行加密。TLS是SSL的升级版。现在提到HTTPS,加密套件基本指的是TLS。

传输加密的流程

原先是应用层将数据直接给到TCP进行传输,现在改成应用层将数据给到TLS/SSL,将数据加密后,再给到TCP进行传输。

HTTPS是如何加密数据的

对安全或密码学基础有了解的同学,应该知道常见的加密手段。一般来说,加密分为对称加密、非对称加密(也叫公开密钥加密)

HTTPS开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性

HTTPS与HTTP的一些区别

  • HTTPS协议需要到CA申请证书,一般免费证书很少,需要交费。
  • HTTP协议运行在TCP之上,所有传输的内容都是明文,内容可能会被窃听。HTTPS运行在SSL/TLS之上,SSL/TLS运行在TCP之上,所有传输的内容都经过加密的。
  • HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
  • HTTPS可以有效的防止运营商劫持,解决了防劫持的一个大问题。
  • 不验证通信方的身份,通信方的身份有可能遭遇伪装。
  • 无法证明报文的完整性,报文有可能遭篡改。

clipboard.png

使用SPDY加快你的网站速度

谷歌推行一种协议(HTTP 之下SSL之上[TCP]),可以算是HTTP2的前身,SPDY可以说是综合了HTTPS和HTTP两者优点于一体的传输协议,比如

  1. 压缩数据(HEADER)
  2. 多路复用
  3. 优先级(可以给请求设置优先级)

SPDY构成图:

clipboard.png

SPDY位于HTTP之下,TCP和SSL之上,这样可以轻松兼容老版本的HTTP协议(将HTTP1.x的内容封装成一种新的frame格式),同时可以使用已有的SSL功能。

HTTP2

HTTP2.0可以说是SPDY的升级版(其实原本也是基于SPDY设计的),但是,HTTP2.0 跟 SPDY 仍有不同的地方,主要是以下两点

  • HTTP2.0 支持明文 HTTP 传输,而 SPDY 强制使用 HTTPS
  • HTTP2.0 消息头的压缩算法采用 HPACK,而非 SPDY 采用的 DEFLATE

http2 新特性

  • 新的二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。
  • 多路复用(MultiPlexing),支持单个连接多次请求,即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。
  • header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
  • 服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。目前,有大多数网站已经启用HTTP2.0,例如YouTuBe,淘宝网等网站,利用chrome控制台可以查看是否启用H2:
chrome=>Network=>Name栏右键=>√Protocol

本节参考文章:简单比较 http https http2HTTPS科普扫盲帖

关于跨域

关于跨域,有两个误区:

  1. ✕ 动态请求就会有跨域的问题

✔ 跨域只存在于浏览器端,不存在于安卓/ios/Node.js/python/ java等其它环境

  1. ✕ 跨域就是请求发不出去了

✔ 跨域请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了之所以会跨域,是因为受到了同源策略的限制,同源策略要求源相同才能正常进行通信,即协议、域名、端口号都完全一致。

同源策略具体限制些什么呢?

  1. 不能向工作在不同源的的服务请求数据(client to server)

但是script标签能够加载非同源的资源,不受同源策略的影响。

  1. 无法获取不同源的document/cookie等BOM和DOM,可以说任何有关另外一个源的信息都无法得到 (client to client)

跨域最常用的方法,应当属CORS

如下图所示:

clipboard.png

只要浏览器检测到响应头带上了CORS,并且允许的源包括了本网站,那么就不会拦截请求响应。

CORS把请求分为两种,一种是简单请求,另一种是需要触发预检请求,这两者是相对的,怎样才算“不简单”?只要属于下面的其中一种就不是简单请求:
(1)使用了除GET/POST/HEAD之外的请求方式,如PUT/DELETE
(2)使用了除Accept/Accept-Language/Content-Language/Last-Event-ID/Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain等几个常用的http头这个时候就认为需要先发个预检请求,预检请求使用OPTIONS方式去检查当前请求是否安全

代码里面只发了一个请求,但在控制台看到了两个请求,第一个是OPTIONS,服务端返回:

详见阮一峰的跨域资源共享CORS详解

clipboard.png

第二种常用的跨域的方法是JSONP

JSONP是利用了script标签能够跨域,如下代码所示:

function updateList (data) {
    console.log(data);
}

$body.append(‘<script src=“http://otherdomain.com/request?callback=updateList"></script>');

代码先定义一个全局函数,然后把这个函数名通过callback参数添加到script标签的src,script的src就是需要跨域的请求,然后这个请求返回可执行的JS文本:// script响应返回的js内容为

updateList([{
    name: 'hello'
}]);

由于它是一个js,并且已经定义了upldateList函数,所以能正常执行,并且跨域的数据通过传参得到。这就是JSONP的原理。

小结

跨域分为两种,一种是跨域请求,另一种访问跨域的页面,跨域请求可以通过CORS/JSONP等方法进行访问,跨域的页面主要通过postMesssage的方式。由于跨域请求不但能发出去还能带上cookie,所以要规避跨站请求伪造攻击的风险,特别是涉及到钱的那种请求。

本节参考文章:我知道的跨域与安全

从浏览器打开到页面渲染完成,发生了什么事情(面试)

主要的过程是:
1.浏览器解析 -> 2.查询缓存 -> 3.dns查询 -> 4.建立链接 -> 5.服务器处理请求 -> 6.服务器发送响应 -> 7.客户端收到页面 -> 8.解析HTML -> 9.构建渲染树 -> 10.开始显示内容(白屏时间) -> 11.首屏内容加载完成(首屏时间) -> 12.用户可交互(DOMContentLoaded) -> 13.加载完成(load)

跳转-->应用缓存-->dns-->tcp-->request-->response

clipboard.png

浏览器输入URL后发生了什么(简化)

本节摘要:

  1. DNS域名解析;
  2. 建立TCP连接;
  3. 发送HTTP请求;
  4. 服务器处理请求;
  5. 返回响应结果;
  6. 关闭TCP连接;
  7. 浏览器解析HTML;
  8. 浏览器布局渲染;

clipboard.png

当我们在浏览器输入网址并回车后,一切从这里开始。

一、DNS域名解析

我们在浏览器输入网址,其实就是要向服务器请求我们想要的页面内容,所有浏览器首先要确认的是域名所对应的服务器在哪里。将域名解析成对应的服务器IP地址这项工作,是由DNS服务器来完成的。

客户端收到你输入的域名地址后,它首先去找本地的hosts文件,检查在该文件中是否有相应的域名、IP对应关系,如果有,则向其IP地址发送请求,如果没有,再去找DNS服务器。一般用户很少去编辑修改hosts文件。

clipboard.png

    DNS服务器层次结构

clipboard.png

浏览器客户端向本地DNS服务器发送一个含有域名www.cnblogs.com的DNS查询报文。本地DNS服务器把查询报文转发到根DNS服务器,根DNS服务器注意到其com后缀,于是向本地DNS服务器返回comDNS服务器的IP地址。本地DNS服务器再次向comDNS服务器发送查询请求,comDNS服务器注意到其www.cnblogs.com后缀并用负责该域名的权威DNS服务器的IP地址作为回应。最后,本地DNS服务器将含有www.cnblogs.com的IP地址的响应报文发送给客户端。

从客户端到本地服务器属于递归查询,而DNS服务器之间的交互属于迭代查询。

正常情况下,本地DNS服务器的缓存中已有comDNS服务器的地址,因此请求根域名服务器这一步不是必需的。

二、建立TCP链接

费了一顿周折终于拿到服务器IP了,下一步自然就是链接到该服务器。对于客户端与服务器的TCP链接,必然要说的就是『三次握手』。

clipboard.png

三次握手

客户端发送一个带有SYN标志的数据包给服务端,服务端收到后,回传一个带有SYN/ACK标志的数据包以示传达确认信息,最后客户端再回传一个带ACK标志的数据包,代表握手结束,连接成功。

上图也可以这么理解:

客户端:“你好,在家不,有你快递。”

服务端:“在的,送来就行。”

客户端:“好嘞。”

TCP三次握手
client----->server:SYN(发起一个TCP连接,同步报文)

server----->client:SYN+ACK(应答报文,表示已创建连接)

client----->server:ACK(应答报文,表示收到已连接)

三、发送HTTP请求

与服务器建立了连接后,就可以向服务器发起请求了。这里我们先看下请求报文的结构(如下图):

clipboard.png

请求报文

在浏览器中查看报文首部(以google浏览器为例):

clipboard.png

请求行包括请求方法、URI、HTTP版本。首部字段传递重要信息,包括请求首部字段、通用首部字段和实体首部字段。我们可以从报文中看到发出的请求的具体信息。具体每个首部字段的作用,这里不做过多阐述。

四、服务器处理请求

服务器端收到请求后的由web服务器(准确说应该是http服务器)处理请求,诸如Apache、Ngnix、IIS等。web服务器解析用户请求,知道了需要调度哪些资源文件,再通过相应的这些资源文件处理用户请求和参数,并调用数据库信息,最后将结果通过web服务器返回给浏览器客户端。

clipboard.png

服务器处理请求

五、返回响应结果

在HTTP里,有请求就会有响应,哪怕是错误信息。这里我们同样看下响应报文的组成结构:

clipboard.png

响应报文

在响应结果中都会有个一个HTTP状态码,比如我们熟知的200、301、404、500等。通过这个状态码我们可以知道服务器端的处理是否正常,并能了解具体的错误。

状态码由3位数字和原因短语组成。根据首位数字,状态码可以分为五类:

clipboard.png

状态码类别

六、关闭TCP连接

为了避免服务器与客户端双方的资源占用和损耗,当双方没有请求或响应传递时,任意一方都可以发起关闭请求。与创建TCP连接的3次握手类似,关闭TCP连接,需要4次握手。

clipboard.png

上图可以这么理解:

客户端:“兄弟,我这边没数据要传了,咱关闭连接吧。”

服务端:“收到,我看看我这边有木有数据了。”

服务端:“兄弟,我这边也没数据要传你了,咱可以关闭连接了。”

客户端:“好嘞。”

由客户端发起的关闭连接
    * client----->server:FIN(请求关闭连接)
    * server----->client:ACK(收到了连接,但不会立即关闭,等到报文都发送完再回复一个FIN)
    * server----->client:FIN
    * client----->server:ACK(收到关闭)
由服务端发起的关闭连接
* 当http设置了keepalive定时关闭,服务端会在结束数据传送后关闭TCP连接

七、浏览器解析HTML

准确地说,浏览器需要加载解析的不仅仅是HTML,还包括CSS、JS。以及还要加载图片、视频等其他媒体资源。

浏览器通过解析HTML,生成DOM树,解析CSS,生成CSS规则树,然后通过DOM树和CSS规则树生成渲染树。渲染树与DOM树不同,渲染树中并没有head、display为none等不必显示的节点。

要注意的是,浏览器的解析过程并非是串连进行的,比如在解析CSS的同时,可以继续加载解析HTML,但在解析执行JS脚本时,会停止解析后续HTML,这就会出现阻塞问题,关于JS阻塞相关问题,这里不过多阐述,后面会单独开篇讲解。

八、浏览器布局渲染

根据渲染树布局,计算CSS样式,即每个节点在页面中的大小和位置等几何信息。HTML默认是流式布局的,CSS和js会打破这种布局,改变DOM的外观样式以及大小和位置。这时就要提到两个重要概念:repaint和reflow。

repaint:屏幕的一部分重画,不影响整体布局,比如某个CSS的背景色变了,但元素的几何尺寸和位置不变。

reflow: 意味着元件的几何尺寸变了,我们需要重新验证并计算渲染树。是渲染树的一部分或全部发生了变化。这就是Reflow,或是Layout。

所以我们应该尽量减少reflow和repaint,我想这也是为什么现在很少有用table布局的原因之一。

最后浏览器绘制各个节点,将页面展示给用户。

拓展阅读:面试必考之http状态码有哪些CDN与DNS知识汇总前端工程师系列,TCP复习及浓缩总结(全干货,支持面试)

推荐必读:5分钟让你明白HTTP协议分分钟让你理解HTTPS

本节参考文章:”天龙八步“细说浏览器输入URL后发生了什么

从浏览器地址栏输入url到显示页面的步骤(以HTTP为例)(详细)

  1. 在浏览器地址栏输入URL
  2. 浏览器查看缓存,如果请求资源在缓存中并且新鲜,跳转到转码步骤

    1. 如果资源未缓存,发起新请求
    2. 如果已缓存,检验是否足够新鲜,足够新鲜直接提供给客户端,否则与服务器进行验证。
    3. 检验新鲜通常有两个HTTP头进行控制Expires和Cache-Control:

      • HTTP1.0提供Expires,值为一个绝对时间表示缓存新鲜日期
      • HTTP1.1增加了Cache-Control: max-age=,值为以秒为单位的最大新鲜时间
  3. 浏览器解析URL获取协议,主机,端口,path
  4. 浏览器组装一个HTTP(GET)请求报文
  5. 浏览器获取主机ip地址(DNS解析),过程如下:

    1. 浏览器缓存
    2. 本机缓存
    3. hosts文件
    4. 路由器缓存
    5. ISP DNS缓存
    6. DNS递归查询(可能存在负载均衡导致每次IP不一样)
  6. 打开一个socket与目标IP地址,端口建立TCP链接,三次握手如下:

    1. 客户端发送一个TCP的SYN=1,Seq=X的包到服务器端口
    2. 服务器发回SYN=1, ACK=X+1, Seq=Y的响应包
    3. 客户端发送ACK=Y+1, Seq=Z
  7. TCP链接建立后发送HTTP请求
  8. 服务器接受请求并解析,将请求转发到服务程序,如虚拟主机使用HTTP Host头部判断请求的服务程序
  9. 服务器检查HTTP请求头是否包含缓存验证信息如果验证缓存新鲜,返回304等对应状态码
  10. 处理程序读取完整请求并准备HTTP响应,可能需要查询数据库等操作
  11. 服务器将响应报文通过TCP连接发送回浏览器
  12. 浏览器接收HTTP响应,然后根据情况选择关闭TCP连接或者保留重用,关闭TCP连接的四次握手如下:

    1. 主动方发送Fin=1, Ack=Z, Seq= X报文
    2. 被动方发送ACK=X+1, Seq=Z报文
    3. 被动方发送Fin=1, ACK=X, Seq=Y报文
    4. 主动方发送ACK=Y, Seq=X报文
  13. 浏览器检查响应状态吗:是否为1XX,3XX, 4XX, 5XX,这些情况处理与2XX不同
  14. 如果资源可缓存,进行缓存
  15. 对响应进行解码(例如gzip压缩)
  16. 根据资源类型决定如何处理(假设资源为HTML文档)
  17. 解析HTML文档,构件DOM树,下载资源,构造CSSOM树,执行js脚本,这些操作没有严格的先后顺序,以下分别解释
  18. 构建DOM树:

    1. Tokenizing:根据HTML规范将字符流解析为标记
    2. Lexing:词法分析将标记转换为对象并定义属性和规则
    3. DOM construction:根据HTML标记关系将对象组成DOM树
  19. 解析过程中遇到图片、样式表、js文件,启动下载
  20. 构建CSSOM树:

    1. Tokenizing:字符流转换为标记流
    2. Node:根据标记创建节点
    3. CSSOM:节点创建CSSOM树
  21. 根据DOM树和CSSOM树构建渲染树:

    1. 从DOM树的根节点遍历所有可见节点,不可见节点包括:

      • script,meta这样本身不可见的标签。
      • 被css隐藏的节点,如display: none
    2. 对每一个可见节点,找到恰当的CSSOM规则并应用
发布可视节点的内容和计算样式
  1. js解析如下:

    1. 浏览器创建Document对象并解析HTML,将解析到的元素和文本节点添加到文档中,此时document.readystate为loading
    2. HTML解析器遇到没有async和defer的script时,将他们添加到文档中,然后执行行内或外部脚本。这些脚本会同步执行,并且在脚本下载和执行时解析器会暂停。这样就可以用document.write()把文本插入到输入流中。同步脚本经常简单定义函数和注册事件处理程序,他们可以遍历和操作script和他们之前的文档内容
    3. 当解析器遇到设置了async属性的script时,开始下载脚本并继续解析文档。脚本会在它下载完成后尽快执行,但是解析器不会停下来等它下载。异步脚本禁止使用document.write(),它们可以访问自己script和之前的文档元素
    4. 当文档完成解析,document.readState变成interactive
    5. 所有defer脚本会按照在文档出现的顺序执行,延迟脚本能访问完整文档树,禁止使用document.write()
    6. 浏览器在Document对象上触发DOMContentLoaded事件
    7. 此时文档完全解析完成,浏览器可能还在等待如图片等内容加载,等这些内容完成载入并且所有异步脚本完成载入和执行,document.readState变为complete,window触发load事件
  2. 显示页面(HTML解析过程中会逐步显示页面)

OSI 七层协议 和 五层网络架构

OSI 七层涵盖:物理层,数据链路层,网络层,传输层,会话层,表示层,应用层;

五层因特网协议栈其实就是:

  1. 应用层(dns,http) DNS解析成IP并发送http请求
  2. 传输层(tcp,udp) 建立tcp连接(三次握手)
  3. 网络层(IP,ARP) IP寻址 为数据在结点之间传输创建逻辑链路
  4. 数据链路层(PPP) 封装成帧 在通信实体间建立数据链路链接
  5. 物理层(利用物理介质传输比特流) 物理传输(然后传输的时候通过双绞线,电磁波等各种介质) 主要定义屋里设备如何传输数据

五层模型就是"会话,表示,应用层"同为一层;

DNS 的大体的执行流程了解么,属于哪个层级?工作在哪个层级?

DNS是应用层协议,事实上他是为其他应用层协议工作的,包括不限于HTTP和SMTP以及FTP,用于将用户提供的主机名解析为ip地址。
具体过程如下:
(1)浏览器缓存: 当用户通过浏览器访问某域名时,浏览器首先会在自己的缓存中查找是否有该域名对应的IP地址(若曾经访问过该域名且没有清空缓存便存在);

(2)系统缓存: 当浏览器缓存中无域名对应IP则会自动检查用户计算机系统Hosts文件DNS缓存是否有该域名对应IP;

(3)路由器缓存: 当浏览器及系统缓存中均无域名对应IP则进入路由器缓存中检查,以上三步均为客户端的DNS缓存;

(4)ISP(互联网服务提供商)DNS缓存: 当在用户客服端查找不到域名对应IP地址,则将进入ISP DNS缓存中进行查询。比如你用的是电信的网络,则会进入电信的DNS缓存服务器中进行查找;(或者向网络设置中指定的local DNS进行查询,如果在PC指定了DNS的话,如果没有设置比如DNS动态获取,则向ISP DNS发起查询请求)

(5)根域名服务器: 当以上均未完成,则进入根服务器进行查询。全球仅有13台根域名服务器,1个主根域名服务器,其余12为辅根域名服务器。根域名收到请求后会查看区域文件记录,若无则将其管辖范围内顶级域名(如.com)服务器IP告诉本地DNS服务器;

(6)顶级域名服务器: 顶级域名服务器收到请求后查看区域文件记录,若无则将其管辖范围内主域名服务器的IP地址告诉本地DNS服务器;

(7)主域名服务器: 主域名服务器接受到请求后查询自己的缓存,如果没有则进入下一级域名服务器进行查找,并重复该步骤直至找到正确记录;

(8)保存结果至缓存: 本地域名服务器把返回的结果保存到缓存,以备下一次使用,同时将该结果反馈给客户端,客户端通过这个IP地址与web服务器建立链接。

DNS 的解析的几个记录类型需要了解:

  • A: 域名直接到 IP
  • CNAME: 可以多个域名映射到一个主机,类似在 Github Page就用 CNAME 指向
  • MX: 邮件交换记录,用的不多,一般搭建邮件服务器才会用到
  • NS: 解析服务记录,可以设置权重,指定谁解析
  • TTL: 就是生存时间(也叫缓存时间),一般的域名解析商都有默认值,也可以人为设置
  • TXT: 一般指某个主机名或域名的说明

于梦中2010
2.1k 声望181 粉丝

前端菜鸟儿,请多关照!