详细解析几个和网络请求有关的类(十四) —— NSHTTPCookie(一)

版本记录

版本号 时间
V1.0 2018.03.14

前言

我们做APP发起网络请求,一般都是使用框架,这些框架的底层也都是苹果的API,接下来几篇就一起来看一下和网络有关的几个类。感兴趣的可以看上面几篇文章。
1. 详细解析几个和网络请求有关的类 (一) —— NSURLSession
2. 详细解析几个和网络请求有关的类(二) —— NSURLRequest和NSMutableURLRequest
3. 详细解析几个和网络请求有关的类(三) —— NSURLConnection
4. 详细解析几个和网络请求有关的类(四) —— NSURLSession和NSURLConnection的区别
5. 详细解析几个和网络请求有关的类(五) —— 关于NSURL加载系统(一)
6. 详细解析几个和网络请求有关的类(六) —— 使用NSURLSession(二)
7. 详细解析几个和网络请求有关的类(七) —— URL数据的编码和解码(三)
8. 详细解析几个和网络请求有关的类(八) —— 处理重定向和其他请求更改(四)
9. 详细解析几个和网络请求有关的类(九) —— 身份验证挑战和TLS链验证(五)
10. 详细解析几个和网络请求有关的类(十) —— 理解获取缓存(六)
11. 详细解析几个和网络请求有关的类(十一) —— Cookies和自定义协议(七)
12. 详细解析几个和网络请求有关的类(十二) —— URL Session的生命周期(八)
13. 详细解析几个和网络请求有关的类(十三) —— NSURLResponse(一)

回顾

上一篇讲述关于NSURLResponse,下面这篇我们就主要看一下NSHTTPCookie


Cookie

首先我们要知道Cookie

Cookie是在客户端存储服务器状态的一种机制,Web服务器可以通过Set-Cookie或者Set-Cookie2 HTTP头部设置Cookie。

Cookie可以分为两类,会话Cookie持久Cookie,会话Cookie是临时Cookie,当前会话结束(浏览器退出)时Cookie会被删除。持久Cookie会存储在用户的硬盘上,浏览器退出,然后重新启动后Cookie仍然存在。会话Cookie和持久Cookie的区别在于过期时间,如果设置了Discard参数(Cookie 版本1)或者没有设置Expires(Cookie版本0)或Max-Age(Cookie版本1)设置过期时间,则此Cookie为会话Cookie。

Cookie有两个版本,一个是版本0(Netscape Cookies)和版本1(RFC 2965),目前大多数服务器使用的Cookie 0。


NSHTTPCookie

在iOS中使用NSHTTPCookie类封装一条cookie,通过NSHTTPCookie的方法读取到cookie的通用属性。

下面我们就先看一下NSHTTPCookie API,会给出详细注释。

#import <Foundation/NSObject.h>

@class NSArray<ObjectType>;
@class NSDate;
@class NSDictionary<KeyType, ObjectType>;
@class NSNumber;
@class NSString;
@class NSURL;

typedef NSString * NSHTTPCookiePropertyKey NS_EXTENSIBLE_STRING_ENUM;

NS_ASSUME_NONNULL_BEGIN

/*!
    @const NSHTTPCookieName
    @discussion Key for cookie name
*/
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieName;

/*!
    @const NSHTTPCookieValue
    @discussion Key for cookie value
*/
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieValue;

/*!
    @const NSHTTPCookieOriginURL
    @discussion Key for cookie origin URL
*/
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieOriginURL;

/*!
    @const NSHTTPCookieVersion
    @discussion Key for cookie version
*/
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieVersion;

/*!
    @const NSHTTPCookieDomain
    @discussion Key for cookie domain
*/
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieDomain;

/*!
    @const NSHTTPCookiePath
    @discussion Key for cookie path
*/
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookiePath;

/*!
    @const NSHTTPCookieSecure
    @discussion Key for cookie secure flag
*/
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieSecure;

/*!
    @const NSHTTPCookieExpires
    @discussion Key for cookie expiration date
*/
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieExpires;

/*!
    @const NSHTTPCookieComment
    @discussion Key for cookie comment text
*/
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieComment;

/*!
    @const NSHTTPCookieCommentURL
    @discussion Key for cookie comment URL
*/
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieCommentURL;

/*!
    @const NSHTTPCookieDiscard
    @discussion Key for cookie discard (session-only) flag
*/
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieDiscard;

/*!
    @const NSHTTPCookieMaximumAge
    @discussion Key for cookie maximum age (an alternate way of specifying the expiration)
*/
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookieMaximumAge;

/*!
    @const NSHTTPCookiePort
    @discussion Key for cookie ports
*/
FOUNDATION_EXPORT NSHTTPCookiePropertyKey const NSHTTPCookiePort;


@class NSHTTPCookieInternal;

/*!
    @class NSHTTPCookie
    @abstract NSHTTPCookie represents an http cookie.
    @discussion A NSHTTPCookie instance represents a single http cookie. It is
    an immutable object initialized from a dictionary that contains
    the various cookie attributes. It has accessors to get the various
    attributes of a cookie.
*/
// @abstract  NSHTTPCookie代表一个http cookie
// @discussion 一个NSHTTPCookie实例代表一个单独的http cookie。 它是一个从包含各种cookie属性的字典中初始化的不可变对象。 它有访问器来获取cookie的各种属性。

@interface NSHTTPCookie : NSObject
{
@private
    NSHTTPCookieInternal * _cookiePrivate;
}

/*!
    @method initWithProperties:
    @abstract Initialize a NSHTTPCookie object with a dictionary of
    parameters
    // 根据字典参数初始化一个NSHTTPCookie对象
    @param properties The dictionary of properties to be used to
    initialize this cookie.
    // 用于初始化cookie的属性字典
    @discussion Supported dictionary keys and value types for the
    given dictionary are as follows.
    // 支持的字典的键值类型如下所示

    All properties can handle an NSString value, but some can also
    handle other types.
    // 所有属性都可以处理一个字符串的值,但是一些也可以处理其他类型

    <table border="1" cellspacing="2" cellpadding="4">
    <tr>
        <th>Property key constant</th>
        <th>Type of value</th>
        <th>Required</th>
        <th>Description</th>
    </tr>
    <tr>
        <td>NSHTTPCookieComment</td>
        <td>NSString</td>
        <td>NO</td>
        <td>Comment for the cookie. Only valid for version 1 cookies and
        later. Default is nil.</td>
    </tr>
    <tr>
        <td>NSHTTPCookieCommentURL</td>
        <td>NSURL or NSString</td>
        <td>NO</td>
        <td>Comment URL for the cookie. Only valid for version 1 cookies
        and later. Default is nil.</td>
    </tr>
    <tr>
        <td>NSHTTPCookieDomain</td>
        <td>NSString</td>
        <td>Special, a value for either NSHTTPCookieOriginURL or
        NSHTTPCookieDomain must be specified.</td>
        <td>Domain for the cookie. Inferred from the value for
        NSHTTPCookieOriginURL if not provided.</td>
    </tr>
    <tr>
        <td>NSHTTPCookieDiscard</td>
        <td>NSString</td>
        <td>NO</td>
        <td>A string stating whether the cookie should be discarded at
        the end of the session. String value must be either "TRUE" or
        "FALSE". Default is "FALSE", unless this is cookie is version
        1 or greater and a value for NSHTTPCookieMaximumAge is not
        specified, in which case it is assumed "TRUE".</td>
    </tr>
    <tr>
        <td>NSHTTPCookieExpires</td>
        <td>NSDate or NSString</td>
        <td>NO</td>
        <td>Expiration date for the cookie. Used only for version 0
        cookies. Ignored for version 1 or greater.</td>
    </tr>
    <tr>
        <td>NSHTTPCookieMaximumAge</td>
        <td>NSString</td>
        <td>NO</td>
        <td>A string containing an integer value stating how long in
        seconds the cookie should be kept, at most. Only valid for
        version 1 cookies and later. Default is "0".</td>
    </tr>
    <tr>
        <td>NSHTTPCookieName</td>
        <td>NSString</td>
        <td>YES</td>
        <td>Name of the cookie</td>
    </tr>
    <tr>
        <td>NSHTTPCookieOriginURL</td>
        <td>NSURL or NSString</td>
        <td>Special, a value for either NSHTTPCookieOriginURL or
        NSHTTPCookieDomain must be specified.</td>
        <td>URL that set this cookie. Used as default for other fields
        as noted.</td>
    </tr>
    <tr>
        <td>NSHTTPCookiePath</td>
        <td>NSString</td>
        <td>NO</td>
        <td>Path for the cookie. Inferred from the value for
        NSHTTPCookieOriginURL if not provided. Default is "/".</td>
    </tr>
    <tr>
        <td>NSHTTPCookiePort</td>
        <td>NSString</td>
        <td>NO</td>
        <td>comma-separated integer values specifying the ports for the
        cookie. Only valid for version 1 cookies and later. Default is
        empty string ("").</td>
    </tr>
    <tr>
        <td>NSHTTPCookieSecure</td>
        <td>NSString</td>
        <td>NO</td>
        <td>A string stating whether the cookie should be transmitted
        only over secure channels. String value must be either "TRUE"
        or "FALSE". Default is "FALSE".</td>
    </tr>
    <tr>
        <td>NSHTTPCookieValue</td>
        <td>NSString</td>
        <td>YES</td>
        <td>Value of the cookie</td>
    </tr>
    <tr>
        <td>NSHTTPCookieVersion</td>
        <td>NSString</td>
        <td>NO</td>
        <td>Specifies the version of the cookie. Must be either "0" or
        "1". Default is "0".</td>
    </tr>
    </table>
    <p>
    All other keys are ignored.
    @result An initialized NSHTTPCookie, or nil if the set of
    dictionary keys is invalid, for example because a required key is
    missing, or a recognized key maps to an illegal value.
    // 所有其他的key被忽略
    // @result  一个初始化的NSHTTPCookie对象,如果字典的键是无效的,那么就是nil。例如,因为一个key缺失,那么对应映射的值就是不合法的。
*/
- (nullable instancetype)initWithProperties:(NSDictionary<NSHTTPCookiePropertyKey, id> *)properties;

/*!
    @method cookieWithProperties:
    @abstract Allocates and initializes an NSHTTPCookie with the given
    dictionary.
    @discussion See the NSHTTPCookie <tt>-initWithProperties:</tt>
    method for more information on the constraints imposed on the
    dictionary, and for descriptions of the supported keys and values.
    @param properties The dictionary to use to initialize this cookie.
    @result A newly-created and autoreleased NSHTTPCookie instance, or
    nil if the set of dictionary keys is invalid, for example because
    a required key is missing, or a recognized key maps to an illegal
    value.
*/
// 这个也是实例化的一个方法
// @abstract 根据给定的字典,分配和实例化一个NSHTTPCookie
// @discussion:请参阅NSHTTPCookie <tt> -initWithProperties </ tt>方法以获取有关对字典施加约束的更多信息,以及有关支持的键和值的说明。
// @param: properties用来初始化这个cookie的字典
// @result:新创建并自动释放的NSHTTPCookie实例,如果字典键集合无效,
// 例如缺少必需的键或者识别的键映射为非法值,则为nil

+ (nullable NSHTTPCookie *)cookieWithProperties:(NSDictionary<NSHTTPCookiePropertyKey, id> *)properties;

/*!
    @method requestHeaderFieldsWithCookies:
    @abstract Return a dictionary of header fields that can be used to add the
    specified cookies to the request.
    @param cookies The cookies to turn into request headers.
    @result An NSDictionary where the keys are header field names, and the values
    are the corresponding header field values.
*/
// @abstract 返回一个头域的字典,可以用于将指定的cookie加入到请求中。
// @param cookies 转化为请求头的cookies
// @result 一个NSDictionary,其中键是标题字段名称,值是相应的标题字段值

+ (NSDictionary<NSString *, NSString *> *)requestHeaderFieldsWithCookies:(NSArray<NSHTTPCookie *> *)cookies;

/*!
    @method cookiesWithResponseHeaderFields:forURL:
    @abstract Return an array of cookies parsed from the specified response header fields and URL.
    @param headerFields The response header fields to check for cookies.
    @param URL The URL that the cookies came from - relevant to how the cookies are interpeted.
    @result An NSArray of NSHTTPCookie objects
    @discussion This method will ignore irrelevant header fields so
    you can pass a dictionary containing data other than cookie data.
*/
// @abstract 返回从指定的响应头字段和URL解析的数组
// @param headerFields 用于检查cookie的响应标题字段
// @param URL Cookie来自的URL - 与Cookie的解释方式有关
// @result NSHTTPCookie对象数组
// @discussion 此方法将忽略不相关的标题字段,因此您可以传递包含非cookie数据的字典

+ (NSArray<NSHTTPCookie *> *)cookiesWithResponseHeaderFields:(NSDictionary<NSString *, NSString *> *)headerFields forURL:(NSURL *)URL;

/*!
    @abstract Returns a dictionary representation of the receiver.
    @discussion This method returns a dictionary representation of the
    NSHTTPCookie which can be saved and passed to
    <tt>-initWithProperties:</tt> or <tt>+cookieWithProperties:</tt>
    later to reconstitute an equivalent cookie.
    <p>See the NSHTTPCookie <tt>-initWithProperties:</tt> method for
    more information on the constraints imposed on the dictionary, and
    for descriptions of the supported keys and values.
    @result The dictionary representation of the receiver.
*/
// @abstract 返回一个表示接收者的字典
// @discussion 这个方法返回一个NSHTTPCookie的字典表示,可以保存并传递
// 给<tt> -initWithProperties </ tt>或<tt> + cookieWithProperties:</ tt>
// 以后重构一个相同的cookie。 <p>请参阅NSHTTPCookie <tt> -initWithProperties </ tt>
// 方法以获取有关对字典施加的约束以及支持的键和值的说明的更多信息。

@property (nullable, readonly, copy) NSDictionary<NSHTTPCookiePropertyKey, id> *properties;

/*!
    @abstract Returns the version of the receiver.
    @discussion Version 0 maps to "old-style" Netscape cookies.
    Version 1 maps to RFC2965 cookies. There may be future versions.
    @result the version of the receiver.
*/
// @abstract 返回接收者的版本
// @discussion Version 0 对应"old-style" Netscape cookies,Version 1 对应RFC2965 cookies,也可能有未来的版本。
// @result 接受者的版本

@property (readonly) NSUInteger version;

/*!
    @abstract Returns the name of the receiver.
    @result the name of the receiver.
*/
@property (readonly, copy) NSString *name;

/*!
    @abstract Returns the value of the receiver.
    @result the value of the receiver.
*/
@property (readonly, copy) NSString *value;

/*!
    @abstract Returns the expires date of the receiver.
    @result the expires date of the receiver.
    @discussion The expires date is the date when the cookie should be
    deleted. The result will be nil if there is no specific expires
    date. This will be the case only for "session-only" cookies.
    @result The expires date of the receiver.
*/
   // @abstract 返回者的结束日期
   // @result 接收者的结束日期
   // @discussion 过期日期是应该删除cookie的日期。 如果没有特定的过期日期,结果将为nil。 
   // 这仅适用于“session-only”cookie。
   // @result 接受者的结束日期

@property (nullable, readonly, copy) NSDate *expiresDate;

/*!
    @abstract Returns whether the receiver is session-only.
    @result YES if this receiver should be discarded at the end of the
    session (regardless of expiration date), NO if receiver need not
    be discarded at the end of the session.
*/
// @abstract 返回接受者是否是session-only
// @result 如果在会话结束时丢弃该接收器(不管截止日期是否),则为YES,
// 如果在会话结束时不需要丢弃接收器,则为NO。

@property (readonly, getter=isSessionOnly) BOOL sessionOnly;

/*!
    @abstract Returns the domain of the receiver.
    @discussion This value specifies URL domain to which the cookie
    should be sent. A domain with a leading dot means the cookie
    should be sent to subdomains as well, assuming certain other
    restrictions are valid. See RFC 2965 for more detail.
    @result The domain of the receiver.
*/
// @abstract 返回接收器的域
// @discussion 该值指定了Cookie应发送到的URL域。 具有前导点的域意味着cookie也应该发送到子域,假设某些其他限制是有效的。 
// 有关更多详细信息,请参阅RFC 2965
// @result 接收者的域

@property (readonly, copy) NSString *domain;

/*!
    @abstract Returns the path of the receiver.
    @discussion This value specifies the URL path under the cookie's
    domain for which this cookie should be sent. The cookie will also
    be sent for children of that path, so "/" is the most general.
    @result The path of the receiver.
*/
// @abstract 返回接受者的路径
// @discussion 该值指定了Cookie应该发送到的Cookie域的URL路径。 该cookie也将被发送给该路径的子路径,所以“/”是最通用的。
// @result 接受者的路径

@property (readonly, copy) NSString *path;

/*!
    @abstract Returns whether the receiver should be sent only over
    secure channels
    @discussion Cookies may be marked secure by a server (or by a javascript).
    Cookies marked as such must only be sent via an encrypted connection to 
    trusted servers (i.e. via SSL or TLS), and should not be delievered to any
    javascript applications to prevent cross-site scripting vulnerabilities.
    @result YES if this cookie should be sent only over secure channels,
    NO otherwise.
*/
// 返回是否接收者应该在安全通道中进行发送。Cookies可能被服务器(或JavaScript)标记为安全。 
// 标记为这样的Cookie只能通过加密连接发送到受信任的服务器(即通过SSL或TLS),
// 并且不应该发送到任何JavaScript应用程序以防止跨站点脚本漏洞。返回YES,
// 如果这个cookie只能通过安全通道发送,否则NO。

@property (readonly, getter=isSecure) BOOL secure;

/*!
    @abstract Returns whether the receiver should only be sent to HTTP servers
    per RFC 2965
    @discussion Cookies may be marked as HTTPOnly by a server (or by a javascript).
    Cookies marked as such must only be sent via HTTP Headers in HTTP Requests
    for URL's that match both the path and domain of the respective Cookies.
    Specifically these cookies should not be delivered to any javascript 
    applications to prevent cross-site scripting vulnerabilities.
    @result YES if this cookie should only be sent via HTTP headers,
    NO otherwise.
*/
// 返回接收器是否只应按RFC 2965发送到HTTP服务器。Cookie
// 可能被服务器(或JavaScript)标记为HTTPOnly。 标记为这样的Cookie只能通过HTTP请求
// 中的HTTP头发送,以匹配相应Cookie的路径和域的URL。 具体来说,
// 这些cookie不应该传递给任何javascript应用程序,以防止跨站点脚本漏洞。
// 如果此cookie只应通过HTTP标头发送,则为YES,否则为NO

@property (readonly, getter=isHTTPOnly) BOOL HTTPOnly;

/*!
    @abstract Returns the comment of the receiver.
    @discussion This value specifies a string which is suitable for
    presentation to the user explaining the contents and purpose of this
    cookie. It may be nil.
    @result The comment of the receiver, or nil if the receiver has no
    comment.
*/
// 返回接受者的描述。此值指定适合向用户演示的字符串,说明此Cookie的内容和用途,
// 它可能是nil。接收者的描述,或者如果接收者没有描述,则为nil。

@property (nullable, readonly, copy) NSString *comment;

/*!
    @abstract Returns the comment URL of the receiver.
    @discussion This value specifies a URL which is suitable for
    presentation to the user as a link for further information about
    this cookie. It may be nil.
    @result The comment URL of the receiver, or nil if the receiver
    has no comment URL.
*/
// 返回接收者的描述URL。该值指定适合向用户呈现的URL作为关于该cookie的
// 进一步信息的链接。 它可能是nil。接收者的描述URL,如果接收者没有描述URL,则为nil。

@property (nullable, readonly, copy) NSURL *commentURL;

/*!
    @abstract Returns the list ports to which the receiver should be
    sent.
    @discussion This value specifies an NSArray of NSNumbers
    (containing integers) which specify the only ports to which this
    cookie should be sent.
    @result The list ports to which the receiver should be sent. The
    array may be nil, in which case this cookie can be sent to any
    port.
*/
// 返回接受者应该被发送的端口列表。此值指定NSNumbers(包含整数)的NSArray,
// 它指定此Cookie应发送到的唯一端口。接收者应该发送到的列表端口。 
// 该数组可能为nil,在这种情况下,此cookie可以发送到任何端口。

@property (nullable, readonly, copy) NSArray<NSNumber *> *portList;

@end

上面就是NSHTTPCookie的API及其注释。

1. 获取Cookie的通用属性

- (NSUInteger)version; 
- (NSString *)name; 
- (NSString *)value; 
- (NSString *)domain;
- (NSString *)path; 
- (BOOL)isSessionOnly;

2. Cookie的初始化

+ (id)cookieWithProperties:(NSDictionary *)properties;
- (id)initWithProperties:(NSDictionary *)properties;

+ (NSArray *)cookiesWithResponseHeaderFields:(NSDictionary *)headerFields forURL:(NSURL *)theURL;

3. 读取所有的属性

- (NSDictionary *)properties;

4. NSHTTPCookie实例与HTTP Cookie header相互转换

使用NSHTTPCookie的类方法可以将NSHTTPCookie实例与HTTP cookie header相互转换。

根据NSHTTPCookie实例数组生成对应的HTTP cookie header

+ (NSDictionary *)requestHeaderFieldsWithCookies:(NSArray *)cookies;

headerFileds中读取到Cookie相关内容,生成NSHTTPCookie实例对象数组。

该方法会忽略headerFileds中与cookie无关的字段,如果headerFileds中的cookie没有指定domain,则使用theURL的domain,如果没有指定path,则使用”/”

除非NSURLRequest明确指定不使用cookie(HTTPShouldHandleCookies设为NO),否则URL loading system会自动为NSURLRequest发送合适的存储cookie。从NSURLResponse返回的cookie也会根据当前的cookie访问策略(cookie acceptance policy)接收到系统中。

后记

本篇我们讲述了关于NSHTTPCookie方面的内容。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容