HTTP协议报文及Chrome Network常用功能

HTTP协议报文

Http协议报文分为【Http请求报文】和【Http响应报文】

HTTP请求报文

Http请求报文由【请求行】、【请求头】、【请求空行】和【请求体】4个部分组成。


请求行

请求行由【请求方法】、【URL】和【HTTP协议版本】3个字段组成,它们用【空格分隔】。
比如 GET /data/info.html HTTP/1.1

HTTP常用方法

  • GET方法:获取资源
  • POST方法:传输实体
  • PUT方法:传输文件
  • HEAD方法:获取报文首部
  • DELETE方法:删除文件
  • OPTIONS方法:询问支持的方法

HTTP协议版本

HTTP0.9

最初的版本,只有一个命令GET,服务器只能回应HTML格式字符串。


HTTP1.0
  1. 引入了新的命令POST和HEAD(http数据头部)命令
    每个TCP连接只能发送一个请求,发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。
  2. 头信息是 ASCII 码,后面数据可为任何格式。服务器回应时会告诉客户端,数据是什么格式,即Content-Type字段的作用。这些数据类型总称为MIME即多用途互联网邮件扩展,每个值包括一级类型和二级类型,预定义的类型,也可自定义类型。

HTTP1.1
  1. 新增方法:PUT、PATCH、OPTIONS、DELETE

  2. 引入了持久连接(persistent connection),即TCP连接默认不关闭,可以被多个请求复用,不用声明Connection: keep-alive。对于同一个域名,大多数浏览器允许同时建立6个持久连接引入了管道机制,即在同一个TCP连接里,客户端可以同时发送多个请求,进一步改进了HTTP协议的效率

  3. 同一个TCP连接里,所有的数据通信是按次序进行的。服务器只能顺序处理回应,前面的回应慢,会有许多请求排队,造成"队头堵塞"(Head-of-line blocking)
    为避免上述问题,两种方法:一是减少请求数,二是同时多开持久连接


HTTP2.0

HTTP2.0是SPDY(谷歌公司研发的https的一种协议)的升级版

  1. 头信息和数据体都是二进制,称为头信息帧和数据帧​( HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多。​二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。)
  2. 复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,且不用按顺序一一对应,避免了“队头堵塞“,此双向的实时通信称为多工(Multiplexing)
  3. 引入头信息压缩机制(header compression),头信息使用gzip或compress压缩后再发送;客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,不发送同样字段,只发送索引号,提高速度(HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。)
  4. HTTP/2 允许服务器未经请求,主动向客户端发送资源,即服务器推送(server push)​

HTTP1.0和HTTP1.1的区别
  1. 长连接
    HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,弥补了HTTP1.0每次请求都要创建连接的缺点
  2. 缓存处理
    在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略
  3. 带宽优化和网络连接的使用
    HTTP1.0中,存在一些浪费带宽的现象,例如:客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),方便了开发者自由的选择以便于充分利用带宽和连接
  4. 错误通知的管理
    在HTTP1.1中新增24个状态响应码,如409(Conflict)表示请求的资源与资源当前状态冲突;.410(Gone)表示服务器上的某个资源被永久性的删除
  5. Host头处理
    在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)

HTTPS与HTTP的一些区别
  1. 【CA证书收费】​​HTTPS协议需要到CA申请证书,一般免费证书很少,需要交费。
  2. 【SSL/TLS -> TCP】​HTTP协议运行在TCP之上,所有传输的内容都是明文,HTTPS运行在SSL/TLS之上,SSL/TLS运行在TCP之上,所有传输的内容都经过加密的。
  3. 【443 -> 80】​HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
  4. 【防劫持】​HTTPS可以有效的防止运营商劫持,解决了防劫持的一个大问题。

请求头

HTTP客户程序(例如浏览器),向服务器发送请求的时候必须指明请求类型(一般是GET或者 POST)。

如有必要,客户程序还可以选择发送其他的请求头。​大多数请求头并不是必需的,但对于POST请求来说 Content-Length必须出现。​

常见的请求头字段含义

  • Accept: 浏览器可接受的MIME类型。
  • Accept-Charset:浏览器可接受的字符集。
  • Accept-Encoding:浏览器能够进行解码的数据编码方式,比如gzip。Servlet能够向支持gzip的浏览器返回经gzip编码的HTML页面。许多情形下这可以减少5到10倍的下载时间。
  • Accept-Language:浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到。
  • Authorization:授权信息,通常出现在对服务器发送的WWW-Authenticate头的应答中。
  • Content-Length:表示请求消息正文的长度。
  • Host: 客户机通过这个头告诉服务器,想访问的主机名。Host头域指定请求资源的Intenet主机和端口号,必须表示请求url的原始服务器或网关的位置。HTTP/1.1请求必须包含主机头域,否则系统会以400状态码返回。
  • If-Modified-Since:客户机通过这个头告诉服务器,资源的缓存时间。只有当所请求的内容在指定的时间后又经过修改才返回它,否则返回304“Not Modified”应答。
  • Referer:客户机通过这个头告诉服务器,它是从哪个资源来访问服务器的(防盗链)。包含一个URL,用户从该URL代表的页面出发访问当前请求的页面。
  • User-Agent:User-Agent头域的内容包含发出请求的用户信息。浏览器类型,如果Servlet返回的内容与浏览器类型有关则该值非常有用。
  • Cookie:客户机通过这个头可以向服务器带数据,这是最重要的请求头信息之一。
  • Pragma:指定“no-cache”值表示服务器必须返回一个刷新后的文档,即使它是代理服务器而且已经有了页面的本地拷贝。From:请求发送者的email地址,由一些特殊的Web客户程序使用,浏览器不会用到它。
  • Connection:处理完这次请求后是否断开连接还是继续保持连接。如果Servlet看到这里的值为“Keep- Alive”,或者看到请求使用的是HTTP 1.1(HTTP 1.1默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个元素时(例如Applet,图片),显著地减少下载所需要的时间。要实现这一点,Servlet需要在应答中发送一个Content-Length头,最简单的实现方法是:先把内容写入 ByteArrayOutputStream,然后在正式写出内容之前计算它的大小。
  • Range:Range头域可以请求实体的一个或者多个子范围。例如,表示头500个字节:bytes=0-499表示第二个500字节:bytes=500-999表示最后500个字节:bytes=-500表示500字节以后的范围:bytes=500-第一个和最后一个字节:bytes=0-0,-1同时指定几个范围:bytes=500-600,601-999但是服务器可以忽略此请求头,如果无条件GET包含Range请求头,响应会以状态码206(PartialContent)返回而不是以200 (OK)。
  • UA-Pixels,UA-Color,UA-OS,UA-CPU:由某些版本的IE浏览器所发送的非标准的请求头,表示屏幕大小、颜色深度、操作系统和CPU类型。

请求空行

它的作用是通过一个空行,告诉服务器请求头部到此为止。


请求体

若方法字段是GET,则此项为空,没有数据若方法字段是POST,则通常来说此处放置的就是要提交的数据

常见的POST BODY格式

  1. application/x-www-form-urlencoded

    POST的默认格式,适合传输ascii字符,短字节

    使用js中URLencode转码方法。包括将name、value中的空格替换为加号;将非ascii字符做百分号编码;将input的name、value用‘=’连接,不同的input之间用‘&’连接。

    百分号编码什么意思呢。比如汉字‘丁’吧,他的utf8编码在十六进制下是0xE4B881,占3个字节,把它转成字符串‘E4B881’,变成了六个字节,每两个字节前加上百分号前缀,得到字符串“%E4%B8%81”,变成九个ascii字符,占九个字节(十六进制下是0x244534254238253831)。

    把这九个字节拼接到数据包里,这样就可以传输“非ascii字符的 utf8编码的 十六进制表示的 字符串的 百分号形式”。同样使用URLencode转码,这种post格式跟get的区别在于,get把转换、拼接完的字符串用‘?’直接与表单的action连接作为URL使用,所以请求体里没有数据;而post把转换、拼接后的字符串放在了请求体里,不会在浏览器的地址栏显示,因而更安全一些。​​

  2. multipart/form-data

    适合传输长字节

    对于一段utf8编码的字节,用application/x-www-form-urlencoded传输其中的ascii字符没有问题,但对于非ascii字符传输效率就很低了(汉字‘丁’从三字节变成了九字节),因此在传很长的字节(如文件)时应用multipart/form-data格式。smtp等协议也使用或借鉴了此格式。

    multipart/form-data将表单中的每个input转为了一个由boundary分割的小格式,没有转码,直接将utf8字节拼接到请求体中,在本地有多少字节实际就发送多少字节,极大提高了效率,适合传输长字节。

  3. raw

    application/json用来告诉服务端消息主体是序列化的JSON字符串​​​text/xml​​

  4. binary
    指的就是一些二进制文件类型。
    如application/pdf,指定了特定二进制文件的MIME类型。
    就像对于text文件类型,若没有特定的子类型(subtype),就使用 text/plain。
    类似的,二进制文件没有特定或已知的 subtype,即使用 application/octet-stream,这是应用程序文件的默认值,一般很少直接使用 。
    对于application/octet-stream,只能提交二进制,而且只能提交一个二进制,如果提交文件的话,只能提交一个文件,后台接收参数只能有一个,而且只能是流(或者字节数组)。
    很多web服务器使用默认的 application/octet-stream 来发送未知类型。出于一些安全原因,对于这些资源浏览器不允许设置一些自定义默认操作,导致用户必须存储到本地以使用。一般来说,设置正确的MIME类型很重要。

  5. GraphQl​

    图状数据查询语言​


HTTP响应报文

Http响应报文由【响应行】、【响应头】和【响应体】3个部分组成。


响应行

响应行一般由【HTTP协议版本】、【状态码】及其【描述】组成
比如 HTTP/1.1 200 OK


响应头

响应头用于描述服务器的基本信息,以及数据的描述,服务器通过这些数据的描述信息,可以通知客户端如何处理等一会儿它回送的数据。

设置HTTP响应头往往和状态码结合起来。例如,有好几个表示“文档位置已经改变”的状态代码都伴随着一个Location头,而401(Unauthorized)状态代码则必须伴随一个WWW-Authenticate头。​

然而,即使在没有设置特殊含义的状态代码时,指定响应头也是很有用的。响应头可以用来完成:设置Cookie,指定修改日期,指示浏览器按照指定的间隔刷新页面,声明文档的长度以便利用持久HTTP连接,……等等许多其他任务。

常见的响应头字段含义

  • Allow:服务器支持哪些请求方法(如GET、POST等)。
  • Content- Type:表示后面的文档属于什么MIME类型。Servlet默认为text/plain,但通常需要显式地指定为text/html。由于经常要设置 Content-Type,因此HttpServletResponse提供了一个专用的方法setContentType。
  • Content-Length:表示内容长度。只有当浏览器使用持久HTTP连接时才需要这个数据。如果你想要利用持久连接的优势,可以把输出文档写入 ByteArrayOutputStram,完成后查看其大小,然后把该值放入Content-Length头,最后通过byteArrayStream.writeTo(response.getOutputStream()发送内容。
  • Set-Cookie:设置和页面关联的Cookie。Servlet不应使用response.setHeader(“Set-Cookie”, …),而是应使用HttpServletResponse提供的专用方法addCookie。
  • Location:这个头配合302状态码使用,用于重定向接收者到一个新URI地址。表示客户应当到哪里去提取文档。Location通常不是直接设置的,而是通过HttpServletResponse的sendRedirect方法,该方法同时设置状态代码为302。【Date】:当前的GMT时间,例如,Date:Mon,31Dec200104:25:57GMT。Date描述的时间表示世界标准时,换算成本地时间,需要知道用户所在的时区。你可以用setDateHeader来设置这个头以避免转换时间格式的麻烦。
  • Server:服务器通过这个头告诉浏览器服务器的类型。Server响应头包含处理请求的原始服务器的软件信息。此域能包含多个产品标识和注释,产品标识一般按照重要性排序。Servlet一般不设置这个值,而是由Web服务器自己设置。
  • Refresh:告诉浏览器隔多久刷新一次,以秒计。
  • Expires:告诉浏览器把回送的资源缓存多长时间,-1或0则是不缓存。
  • Content-Encoding:文档的编码(Encode)方法。只有在解码之后才可以得到Content-Type头指定的内容类型。利用gzip压缩文档能够显著地减少HTML文档的下载时间。Java的GZIPOutputStream可以很方便地进行gzip压缩,但只有Unix上的Netscape和Windows上的IE4、IE5才支持它。因此,Servlet应该通过查看Accept-Encoding头(即request.getHeader(“Accept- Encoding”))检查浏览器是否支持gzip,为支持gzip的浏览器返回经gzip压缩的HTML页面,为其他浏览器返回普通页面。
  • Last-Modified:文档的最后改动时间。客户可以通过If-Modified-Since请求头提供一个日期,该请求将被视为一个条件GET,只有改动时间迟于指定时间的文档才会返回,否则返回一个304(Not Modified)状态。Last-Modified也可用setDateHeader方法来设置。
  • Transfer-Encoding:告诉浏览器数据的传送格式。
  • WWW-Authenticate:客户应该在Authorization头中提供什么类型的授权信息?在包含401(Unauthorized)状态行的应答中这个头是必需的。例如,response.setHeader(“WWW-Authenticate”, “BASIC realm=\”executives\”“)。注意Servlet一般不进行这方面的处理,而是让Web服务器的专门机制来控制受密码保护页面的访问。​

注:设置响应最常用的方法是HttpServletResponse的setHeader,该方法有两个参数,分别表示响应头的名字和值。和设置状态代码相似,设置响应头应该在发送任何文档内容之前进行。

setDateHeader 设置包含日期的响应头 避免了把Java时间转换为GMT时间字符串
setIntHeadr 设置包含整数值的响应头 避免了把整数转换为字符串

HttpServletResponse还提供了许多设置

setContentType:设置Content-Type头。大多数Servlet都要用到这个方法。
setContentLength:设置Content-Length头。对于支持持久HTTP连接的浏览器来说,这个函数是很有用的。addCookie:设置一个Cookie(Servlet API中没有setCookie方法,因为应答往往包含多个Set-Cookie头)。


响应体

响应体就是响应的消息体,如果是纯数据就是返回纯数据,如果请求的是HTML页面,那么返回的就是HTML代码,如果是JS就是JS代码,如此之类。


Chrome Network常用功能

General

通用部分.png
  • Request URL:请求的URL
  • Request Method:请求使用的方法
  • Status Code:响应状态码
  • Remote Address:远程服务器的地址和端口
  • Reffer Policy:Referrer判别策略

Response Header

响应头部分.jpg
  • Date:标识产生响应的时间
  • Content-Encoding:指定响应内容编码
  • Server:包含服务器信息,如名称,版本号等
  • Content-Type:文档类型,指出返回的数据类型是什么。如此处的text/html代表返回的是HTML代码
  • Set-Cookie:设置Cookies。响应头中的Set-Cookie告诉浏览器要将此内容放在Cookies中,下次请求携带Cookies请求
  • Expires:指定响应过期时间,可以使代理服务器将加载的内容更新到缓存当中。如果再次访问,就可直接从缓存中加载,降低服务器的负载,缩短加载时间。

Request Headers

请求头部分.png
  • Accept:请求报头域,用于指定客户端可接受哪些信息类型
  • Accept-Encoding:指定客户端可接受的语言类型
  • Accept-Language:指定客户端可接受的内容编码
  • Host:指定请求资源的主机IP和端口号,其为请求URL的原始服务器或网关的位置
  • Cookie:网站为了辨别用户进行会话跟踪而储存在用户本地的数据。主要功能是维持当前访问会话。(非常重要!!!)
  • Referer:用来标识这个请求是从哪个网页过来的。服务器拿到这一信息并做相应的处理,如来源统计,防盗链等
  • User-Agent:一个特殊的字符串头,可以使服务器识别客户使用的操作系统及版本等信息。在做爬虫时一定要加上此信息
  • Content-Type:互联网媒体类型,在HHTP协议消息中,用来表示具体请求中的媒体信息类型

Preview

Response preview 响应预览

在Preview(预览功能)中,控制台会把发送过来的json数据自动转换成javascript的对象格式。

Response

Raw Response Data 原始响应数据

原始响应数据

Initiator

Request initiator call stack 请求发起方调用栈

Timing

请求/响应时间线
  • Queueing(排队):浏览器在以下情况下将请求排队:
    有更高优先级的请求。
    已为该来源打开了六个TCP连接。仅适用于HTTP/1.0和HTTP/1.1。
    浏览器正在磁盘缓存中短暂分配空间
  • Stalled:出于Queueing中描述的任何原因,该请求都可能被暂停
  • DNS Lookup:浏览器正在解析请求的IP地址
  • Proxy negotiation:浏览器正在与代理服务器协商请求
  • Request sent:请求发送时间
  • ServiceWorker Preparation:浏览器正在启动service worker
  • Request to ServiceWorker:请求发送到service worker的时间
  • Waiting (TTFB): 浏览器等待第一个字节响应的时间
  • Content Download:响应内容下载时间
  • Receiving Push:浏览器正在通过HTTP/2服务器推送接收此响应的数据
  • Reading Push: 浏览器正在读取先前接收的本地数据。

Cookies

Request and response cookies 请求/响应Cookies

show filtered out request cookies

显示被过滤的Cookie

SameSite

用来限制第三方 Cookie,从而减少安全风险

  • Strict
    Strict最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。
  • Lax (默认)
    Lax规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外。
  • None
    Chrome 将Lax变为默认设置。网站可以选择显式关闭SameSite属性,将其设为None。​不过,前提是必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容

  • http协议有http0.9,http1.0,http1.1和http2三个版本,但是现在浏览器使用的是htt...
    一现_阅读 1,855评论 0 3
  • 深入浅出HTTP协议(WEB开发和面试必备) 1.基础概念篇 a.简介 HTTP是Hyper Text Trans...
    半世韶华忆阑珊阅读 1,211评论 0 7
  • 本文整理自MIN飞翔博客 [1] 1. 概念 协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或...
    HoyaWhite阅读 2,634评论 2 20
  • HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从服务器传输...
    blossomjae阅读 780评论 0 1
  • 复盘一下今天: 早上八点下夜班,有一个病人问为什么多发了一个口服药,回想了一下,这二天刚给她加的一个止痛的药,就把...
    米瞪眼的糖豆豆阅读 95评论 0 1