HTTP详细总结

HTTP详细总结

一、前言

URI

URI(统一资源标识符):我们使用HTTP协议,主要就用来访问互联网上的各种资源,而URI就用来标识这些资源在互联网上的位置,包括两种最常见的方式:URL和URN。
语法:{方案或协议} {主机+端口} {路径} {查询} {锚点}
例如:http://www.example.com:80/path/to/myfile.html?key1=value2&key2=value2#title

协议

协议:http://告诉浏览器采用何种协议,常见的协议有:

协议 描述 作用
data Data URIs
file 本地文件传输协议 访问本地计算机中的文件
ftp 文件传输协议 主要用于远程文件传输
http/https 超文本传输协议/安全的超文本传输协议
mailto 电子邮件协议 用于通知浏览器调用本地邮件客户端发送邮件
ssh 安全外壳协议 提供安全加密的网络传输环境
tel 电话协议 用于通知浏览器调用本地电话客户端发起通话请求
urn 统一资源名称 统一资源名称
view-source 资源源代码 后接资源url可以查看资源源代码
ws/wss WebSocket连接协议 websocket

MIME类型 {#mime}

多用途Internet邮件扩展(MIME)类型 是一种标准化的方式来表示文档的性质和格式。在Windows上我们通常使用文件扩展名来区分使用何种软件来处理文档,而浏览器通常使用MIME类型(而不是文件扩展名)来确定如何处理文档,所以服务器应该在响应对象的头部设置正确的MIME类型。

  • 语法:type/subtype

    MIME的组成结构非常简单;由类型与子类型两个字符串中间用'/'分隔而组成。不允许空格存在。type 表示可以被分多个子类的独立类别。subtype 表示细分后的每个类型。
    MIME对大小写不敏感,但是通常使用全小写形式。

  • 独立类型:独立类型表明了对文件的分类,有如下几种:

    类型 描述 典型实例
    text 普通文本 text/plain;text/html;text/css
    image 图像,包括动图 image/gif;image/png;image/jpeg;image/bmp
    audio 音频 audio/midi;audio/mpeg;audio/ogg
    video 视频 video/webm;video/ogg
    application 某种二进制数据 application/octet-stream;application/xml;application/pdf

    对于text类型,如果没有特定的子类型,则默认text/plain;类似的,application类型默认为application/octet-stream。

  • Multipart类型:复合文件一种类型。

    • multipart/form-data:用于表示表单POST时的数据。

    • multipart/byteranges:用于把部分的响应报文发送回浏览器。

      使用状态码206 Partial Content来发送整个文件的子集,而HTTP对不能处理的复合文件使用特殊的方式:将信息直接传送给浏览器(这时可能会建立一个“另存为”窗口,但是却不知道如何去显示内联文件。)。当发送状态码206Partial Content 时,这个MIME类型用于指出这个文件由若干部分组成,每一个都有其请求范围。就像其他很多类型Content-Type使用分隔符来制定分界线。每一个不同的部分都有Content-Type这样的HTTP头来说明文件的实际类型,以及 Content-Range来说明其范围。

  • 几种重要的MIME类型

    • text/plain:纯文本
    • text/css:css样式表文件
    • text/html:html文件
    • application/octet-stream:二进制流
    • application/javascript:js文件
    • application/json:json文件
    • application/xml:xml文件
    • application/pdf:pdf文件
    • multipart/form-data:表单提交
      如下为一个包含附件的提交:
      POST /site/file/upload HTTP/1.1
      Host: myhost
      Connection: keep-alive
      Content-Length: 46492
      Origin: http://myhost
      User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36
      Content-Type: multipart/form-data; boundary=----WebKitFormBoundary5jBgoLfQFCAe9xpw
      Accept: */*
      Accept-Encoding: gzip, deflate
      Accept-Language: zh-CN,zh;q=0.9
      Cookie: Company_ID=EINK;
      
      ------WebKitFormBoundary5jBgoLfQFCAe9xpw
      Content-Disposition: form-data; name="property1"
      
      CustomMethod.dll
      ------WebKitFormBoundary5jBgoLfQFCAe9xpw
      Content-Disposition: form-data; name="property2"
      
      30
      ------WebKitFormBoundary5jBgoLfQFCAe9xpw
      Content-Disposition: form-data; name="file"; filename="CustomMethod.dll"
      Content-Type: application/x-msdownload
      
      ------WebKitFormBoundary5jBgoLfQFCAe9xpw--
      
      以上请求需注意的是,Content-Type为multipart/form-data,且请求体里可以看到,除上传文件CustomMethod.dll外,还包括property1和property2两对值一并提交了。
  • 几种可能会用到的MIME类型

    • image/jpeg:jpeg、jpg文件
    • image/gif:gif文件
    • image/x-ico:icon图标文件
    • application/msword:Word文件
    • application/vnd.ms-excel:excel文件
    • application/x-rar-compressed:rar文件
  • 设置正确MIME类型的重要性

    再次重申,浏览器是以MIME作为处理文件的依据,如果一个link标签内的css文件被指定为text/plain,浏览器不会将其解析为css文件。

二、HTTP概览

HTTP协议

HTTP协议(超文本传输协议)是互联网上最广泛的一种网络协议。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。通过HTTP或者HTTPS协议请求的资源由统一资源标识符来标识。

HTTP请求过程

HTTP请求过程

客户端(User-Agent)

一般为用户浏览器。

服务端(Web-Server)

一台或一组能提供Web服务的计算机。

代理(Proxies)

在浏览器和服务器之间有许多机器或设备转发了HTTP消息,这些设备分布于传输层、网络层或者物理层上,而有一些位于应用层,他们就是代理,代理对于客户端和服务器来说既可以是透明的,也可以是可见的。而代理既可能改变HTTP消息,也可能不改变,这就要看代理的具体作用了。各种代理有如下几种作用:

  • 转发:单纯不做任何操作,比如大多数企业内网,通过一台代理服务器来访问外网。或将特定请求转发到其他地址。
  • 缓存。
  • 过滤:同样一些企业内网的代理会做一些反病毒扫描、家长控制等。
  • 认证:完成一些身份认证的工作,或者对不同资源进行权限管理。
  • 日志:比如在现有系统不做改变的情况下,使用nginx代理实现日志记录。

特点

  • 可读性:HTTP协议被设计的很简单易读。
  • 可扩展:扩展性强,只需客户端与服务器就新header达成一致即可轻易实现扩展。
  • 无状态:HTTP是无状态的,在同一个连接中的两次连续的请求是没有关系的。尽管如此,仍然可以通过把cookie添加到header中获取上下文信息来解决此问题。

作用

  • 缓存:使用cache相关的header等来控制缓存。服务端能告诉浏览器或代理哪些文档需要被缓存,缓存多久;同时浏览器也能告诉代理哪些文档请求需要忽略。
  • 认证:使用Authenticate相似的头部即可实现对特定的页面进行保护,同时也可以通过cookie来实现相应功能。
  • 代理:代理就是基于HTTP或socket层面。
  • 会话:使用cookie来传递上下文信息。
  • 开放同源策略:可以通过修改HTTP头部一些信息解除同源限制。

三、HTTP报文

HTTP会话包括客户端发送请求、建立连接、服务端返回响应,建立连接发生在传输层,通常为TCP连接,默认80端口。C-S模型不允许服务器在没有显示发送请求时向客户端发送数据,不过现在开发使用其他技术,如XMLHTTPRequest或Fetch API周期性地请求服务器,以达到类似效果。
客户端发送请求与服务端返回响应分别对应HTTP报文中得请求报文和响应报文。

HTTP请求报文

HTTP请求报文包括请求行、请求头、空行和请求体四部分组成,空行用来隔开请求头与请求体,如下图:

HTTP请求报文

百度首页的请求头如下:

GET / HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: BAIDUID=51DCFC83838328932381GS62F770DA7:FG=1;

请求行

请求行由请求的HTTP方法、路径、协议版本三部分组成。
请求方法有:GET、POST、PUT、DELETE、HEAD、CONNECT、OPTIONS、TRACE、PATCH。常用的有GET、POST、PUT、DELETE。

  • GET:GET方法请求一个指定资源的表示形式. 使用GET的请求应该只被用于获取数据。
  • HEAD:HEAD方法请求一个与GET请求的响应相同的响应,但没有响应体。
  • POST:POST方法用于将实体提交到指定的资源,通常导致状态或服务器上的副作用的更改。
  • PUT:PUT方法用请求有效载荷替换目标资源的所有当前表示。
  • DELETE:DELETE方法删除指定的资源。
  • CONNECT:CONNECT方法建立一个到由目标资源标识的服务器的隧道。
  • OPTIONS:OPTIONS方法用于描述目标资源的通信选项。
  • TRACE:TRACE方法沿着到目标资源的路径执行一个消息环回测试。
  • PATCH:PATCH方法用于对资源应用部分修改。

请求头

请求头包含多组由分隔的键值对,用来告诉服务器一些与请求相关的信息。常用头信息后边有写。

请求体

请求体同请求一起发送到服务器端,一般用来更新数据,常用在POST请求,而GET、OPTIONS亲请求一般用来获取数据,不需要发送请求体。
请求体分为两种:

  • Single-resource bodies:由单个文件组成,该类型body通过Content-Type和Content-Length来定义,如json数据,Content-Type:application/json,如下:
    POST /GAIA_FB/Account/Logon HTTP/1.1
    Host: testsite.com
    Connection: keep-alive
    Content-Length: 144
    Accept: application/json, text/javascript, */*; q=0.01
    Origin: http://www.testsite.com
    X-Requested-With: XMLHttpRequest
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36
    Content-Type: application/json
    Referer: http://testsite.com/Account/logon
    Accept-Encoding: gzip, deflate
    Accept-Language: zh-CN,zh;q=0.9
    Cookie: CULTURE_CODE=zh-CN; loginfrom=aVgy0ql016TDtCp8QAsi0Q==
    
    {
        account: "rascalquan",
        cultureCode: "zh-CN",
        password: "112233",
        returnUrl: ""
    }
    
  • Multiple-resource bodies:由多部分 body 组成,每一部分包含不同的信息位。通常是和HTML Forms连系在一起,如附件上传时,如下,Content-Type:multipart/form-data
    POST /GAIA_FB/file/upload HTTP/1.1
    Host: testsite.com
    Connection: keep-alive
    Content-Length: 32159
    Origin: http://www.testsite.com
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36
    Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryI93ysNPTg7vxds7O
    Accept: */*
    Referer: http://www.testsite.com/fileUpload
    Accept-Encoding: gzip, deflate
    Accept-Language: zh-CN,zh;q=0.9
    Cookie: CULTURE_CODE=zh-CN; loginfrom=aVgy0ql016TDtCp8QAsi0Q==;
    
    ------WebKitFormBoundaryI93ysNPTg7vxds7O
    Content-Disposition: form-data; name="prop1"
    
    UsbkeyImport.xls
    ------WebKitFormBoundaryI93ysNPTg7vxds7O
    Content-Disposition: form-data; name="file"; filename="UsbkeyImport.xls"
    Content-Type: application/vnd.ms-excel
    
    ------WebKitFormBoundaryI93ysNPTg7vxds7O--
    

HTTP响应报文

HTTP响应报文包括状态行、响应头、空行和响应报文体四部分组成,空行用来隔开响应头与响应报文体,如下图:

HTTP响应报文

状态行

状态行由协议版本、响应码、响应状态描述组成。

状态码

响应头

响应头与请求头类似,包含多组由分隔的键值对,用来描述服务器的一些相关的信息。

响应报文体

响应报文体即响应的主体,如HTML页面、JPEG图片、PDF文件等等,浏览器会根据响应头中的Content-Type设置的MIME选择相应的处理方式,是该呈现还是下载附件。

常用Header

各Header按照用途可以分为请求头(只用在请求时)、响应头(只用在响应时)、通用头(请求和响应时都可使用)三种。有些可在代码里修改,有些不可修改,由用户代理自行维护,如Date头。

  • Accept:表示客户端可以接受或处理的MIME类型,服务端从多项类型中选择一项并以Content-Type回应。
    基本语法:<MIME_type>/<MIME_subtype>[;q=权重]
    其中q代表权重,表示优先级,多个类型之间用,隔开。
    <MIME_type>/**/*代表任意子类型或任意类型。
    示例:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8
  • Accept-Charset:表示客户端可以接受或处理的字符集类型,服务端从多项类型中选择一项并以Content-Type回应。
    基本语法:<charset>[;q=权重],字符集如utf-8或iso-8859-15等。
    其中q代表权重,表示优先级,多个类型之间用,隔开。
    不过,一般浏览器不会也不用提供,以各类型的默认值即可。
  • Accept-Encoding:表示客户端可以接受或处理的压缩编码类型。
  • Accept-Language:表示客户端可以接受的自然语言。
  • Connection:表示当前事务完成后是否关闭连接。
    用法:
    Connection:Keep-Alive //保持连接
    Connection:Close //关闭连接
  • Content-Disposition:指示响应的内容作为内联形式内嵌到页面中还是附件形式下载到本地。
    用法:
    Content-Disposition:inline //内联形式,默认
    Content-Disposition:attachment;filename="filename1.jpg" //附件形式,浏览器会弹出另存为的提示框,filename为下载时另存为的文件名
    Content-Disposition:form-data;name="field1";filename="filename1.jpg" //用于类型为multipate body时,多为表单提交,可看上文中MIME类型的Multipart类型中multipart/form-data

四、Cookie

概述

HTTP Cookie是服务器发送到浏览器并保存在浏览器端的一小块数据,它会在浏览器下次同一服务器时一并发送给服务器。Cookie使无状态的HTTP记录稳定的状态成为了可能。

Cookie作用

  • 会话管理:记录用户的登录状态、访问状态等,记录登录状态是cookie最常用的功能,通常服务器会在用户登录成功后下发一个sessionid以免去每次登录。记录访问状态可以保持用户的浏览记录,如购物车等信息。
  • 个性设置:记录用户一些自定义设置,如将主题、语言等的设置保存在cookie中。
  • 行为追踪:跟踪并分析用户的行为,如Google投放的广告等。

使用

创建Cookie

服务器通过在响应头添加Set-Cookie: <cookie名>=<cookie值>来告知浏览器需要保存cookie,当浏览器看到该响应头后就会把其中的cookie键值对保存下来,并在后续的请求中自动添加cookie:<cookie名>=<cookie值>请求头。

  • 会话期Cookie:像<cookie名>=<cookie值>这样的cookie就是会话期cookie,只在这次会话期间生效,当关闭浏览器后就会自动删除。
  • 持久性Cookie:通过为cookie设置Expires(特定过期时间)或Max-Age(有效秒数)属性可以实现cookie的持久化保存。如Set-Cookie: id=a3fWa; Expires=Thu Nov 22 2018 16:25:27 GMT;设置cookie id为特定的失效时间2018/11/22 16:25:27。如Set-Cookie: id=a3fWa; Max-Age=1000;设置cookie id在1000秒后失效。

访问Cookie

  • HTTP访问:从Cookie请求头直接访问。
  • Javascript访问:对于非HttpOnly标记的cookie可以通过document.cookie访问或修改cookie。

Cookie安全

可以为cookie添加Secure或HttpOnly标记。
添加了Secure标记的cookie只有在https加密时才会发送给服务器以保证cookie不会被截取,如Set-Cookie: id=a3fWa;Secure。尽管如此,还是不建议将敏感信息,如密码,放在cookie中
添加了HttpOnly标记的cookie只在发送HTTP消息时才能被发现,而不能被js抓取到,避免了XSS(跨域脚本攻击)的危害。

Cookie作用域

Domain 和 Path 标识定义了Cookie的作用域:即Cookie应该发送给哪些URL。
Domain标识了哪些主机可以接收cookie,如果不指定,则默认只有当前主机(不包含子域名)可以接收该cookie;如果指定了Domain,则一般包括子域名也可接收。
Path标识了哪些路径(及其子路径)可以接收该cookie。如Set-Cookie: id=a3fWa;path=\docs

五、Cache

Cache概述

常用的缓存有数据库缓存、服务器端缓存、浏览器端缓存等,Cache即浏览器端缓存,当浏览器请求一个web资源后,在浏览器端保存一份该资源的副本,当下次再次请求相同资源时,如果满足特定条件则直接返回该资源的副本,而无需再次发起请求。
合理利用缓存有助于:

  1. 缓解服务器压力
  2. 减少网络带宽
  3. 加快响应速度

Cache三大策略

Cache缓存的工作原理包括三大策略:缓存存储策略、缓存过期策略、缓存验证策略。三大策略分别处理缓存的是否存储、何时过期、验证缓存是否有效。

缓存存储策略

与缓存存储策略相关的有Cache-Control的几个header和Pragma

  • Cache-Control:Private:缓存,只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它),可以缓存响应内容。
  • Cache-Control:Public:缓存,可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存。
  • Cache-Control:no-cache:缓存,但强制将请求提交给原始服务器进行验证。
  • Cache-Control:only-if-cached:表明客户端只接受已缓存的响应,并且不要向原始服务器检查是否有更新的拷贝。
  • Cache-Control:max-age:缓存,设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。
  • Cache-Control:no-store:不缓存。
  • Pragma:no-cache:同Cache--Control:no-cache,强制缓存验证,上古产物,不建议使用了。

无法被缓存的情况:

  • 响应头中包含Cache-Control:no-store头的请求无法被缓存
  • 响应头中包含Cache-Control:max-age=0的请求无法被缓存
  • 响应头中不包含Last-Modified/Etag,也不包含Cache-Control/Expires的请求无法被缓存
  • POST请求无法被缓存

缓存过期策略

与缓存过期策略相关的HTTP头:

  • Cache-Control:max-age:缓存存储的最大周期,优先级高于Expires。
  • Expires:即在此时候之后,缓存过期。

缓存过期并不意味着缓存被删除或失效,即使缓存过期了还是有可能使用的。后边的缓存验证策略中会讲到。

缓存验证策略

当缓存的文档过期后,需要进行缓存验证或者重新获取资源。只有在服务器返回强校验器或者弱校验器时才会进行验证

弱校验器:Last-Modified 响应头可以作为一种弱校验器。说它弱是因为它只能精确到一秒。如果响应头里含有这个信息,客户端可以在后续的请求中带上 If-Modified-Since:Last-Modified-valueIf-Unmodified-Since:Last-Modified-value 来验证缓存。

  • If-Modified-Since:是否在指定时间之后做了修改,将上次响应头中的Last-Modified的值发给服务器验证,如果服务器资源在此之后有做修改,则返回新的资源,状态码200,否则返回一个不带消息主体的304响应,以告诉浏览器使用缓存即可。通常只用在GET、HEAD请求中。
  • If-Unmodified-Since:是否在指定时间之后未做修改,类似if-Modified-Since,不过通常只用于POST请求。如并发修改时,未防止覆盖修改,如果请求的资源在指定时间之后发生了修改,则返回412(前提条件失效)错误,如果未修改,则做出修改,并返回200。

强校验器:ETag可以唯一标识一份资源,可以通过特定计算获得(如md5),如果响应头里含有这个信息,客户端可以在后续的请求中带上 If-Match:ETag-valueIf-None-Match:ETag-value 来验证缓存。尽管ETag比Last-Modified准确很多,但是对ETag的计算会消耗一定的服务器资源或客户端资源。

  • If-None-Match:配合ETag使用,当且仅当服务器上没有任何资源的 ETag 属性值与这个首部中列出的相匹配的时候,服务器端会才返回所请求的资源(GET、HEAD)或对服务器资源做修改(POST、PUT),响应码为200 ,否则返回304响应码(GET、HEAD)或412错误(POST、PUT)。
  • If-Match:类似If-None-Match,验证通过则返回200,否则返回412。If-Match与if-None-Match优先级高于if-Modified-Since与if-Unmodified-Since。

如图:


缓存策略

访问方式

用户访问方式可以总结为三种:

  1. 直接访问:点击超链接、地址栏输入URL的方式,会进行普通的缓存验证策略。
  2. 刷新页面:点击刷新按钮、F5、右键重新加载,会强制验证缓存,在请求头中加上If-Modified-SinceIf-None-Match,如果满足验证则返回资源,否则返回304来从缓存获取资源。
  3. Ctrl+F5:不采取缓存,强制服务器重新发送完整请求,这时请求头即没有If-Modified-Since也没有If-None-Match

缓存实践

综上对各种HTTP缓存控制头部的对比以及用户可能出现的浏览器刷新行为的讨论,当我们在一个项目上做http缓存的应用时,我们实际上还是会把上述提及的大多数首部字段均使用上。

  1. Expires / Cache-Control
    Expires用时刻来标识失效时间,不免收到时间同步的影响,而Cache-Control使用时间间隔很好的解决了这个问题。 但是 Cache-Control 是 HTTP1.1 才有的,不适用于 HTTP1.0,而 Expires 既适用于 HTTP1.0,也适用于 HTTP1.1,所以说在大多数情况下同时发送这两个头会是一个更好的选择,当客户端两种头都能解析的时候,会优先使用 Cache-Control。
  2. Last-Modified / ETag
    二者都是通过某个标识值来请求资源, 如果服务器端的资源没有变化,则自动返回 HTTP 304 (Not Changed)状态码,内容为空,这样就节省了传输数据量。而当资源发生比那话后,返回和第一次请求时类似。从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。
    其中Last-Modified使用文件最后修改作为文件标识值,它无法处理文件一秒内多次修改的情况,而且只要文件修改了哪怕文件实质内容没有修改,也会重新返回资源内容;ETag作为“被请求变量的实体值”,其完全可以解决Last-Modified头部的问题,但是其计算过程需要耗费服务器资源。
  3. from-cache / 304
    Expires和Cache-Control都有一个问题就是服务端作为的修改,如果还在缓存时效里,那么客户端是不会去请求服务端资源的(非刷新),这就存在一个资源版本不符的问题,而强制刷新一定会发起HTTP请求并返回资源内容,无论该内容在这段时间内是否修改过;而Last-Modified和Etag每次请求资源都会发起请求,哪怕是很久都不会有修改的资源,都至少有一次请求响应的消耗。
    对于所有可缓存资源,指定一个Expires或Cache-Control max-age以及一个Last-Modified或ETag至关重要。同时使用前者和后者可以很好的相互适应。
    前者不需要每次都发起一次请求来校验资源时效性,后者保证当资源未出现修改的时候不需要重新发送该资源。而在用户的不同刷新页面行为中,二者的结合也能很好的利用HTTP缓存控制特性,无论是在地址栏输入URI然后输入回车进行访问,还是点击刷新按钮,浏览器都能充分利用缓存内容,避免进行不必要的请求与数据传输。
  4. 避免304
    对于一些css或js等静态文件,不会频繁更新,但每次更新后又需保证客户端能获取到最新,而不是从缓存中获取。可以在url后添加版本号(?md5?version)的方式模拟服务端ETag的原理。而每次更新资源后只需更新其版本号即可,同时为其设置一个较长的Expire或max-age。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335