聚合数据API查询快递数据-短信验证码

有位朋友让我给他新开的网站帮忙做几个小功能,如下:
1.输入快递公司、快递单号,查询出这个快件的所有动态(从哪里出发,到了哪里)
2.在注册、登录等场景下的手机验证码(要求有一定的防刷策略)
3.通过输入公司名的关键词,查看这个公司是否已经注册、法人信息、有类似名称的公司等等
并且可以用的接口、文档都提供给我了。其中需求 1、2,都通过 聚合数据 这家网站提供的接口实现;需求 3 通过 云聚数据 来实现。

本项目的文件
因为朋友的网站是用 ThinkPHP 写的,为了保持将来代码的兼容,这三个功能也用 ThinkPHP 写成。
项目的所有文件都放在了 GitHub 上,部分敏感数据已经隐藏,你需要自行替换,地址如下:
GitHub 地址:使用聚合数据API查询快递数据-短信验证码-企业核名
因为这三个功能并不是正式产品,将来会需要嵌入到网站的各个功能模块中去,所以为了查看起来方便,三个功能的代码都写在一个文件里,你只要重点关注以下几个文件就好:
/Home/Conf/config.php
参数配置文件
/Home/Controller/IndexController.class.php
后端代码、API的请求与处理
/Home/View/Index_index.html
前端 html

申请 KEY 和阅读开发文档
分别到上面两家网站上找到“快递”、“短信”、“核名”的文档地址,根据里面的说明,把 KEY、URL 等信息放入配置文件Home/Conf/config.php
,方便后面重复使用。
常用快递API文档
短信API文档
核名-文档
注意 短信的 API 服务,要先到网站的后台添加“短信模板”,让管理员审核后才可以正常调用
最后,Home/Conf/config.php
配置文件里的内容如下

return array(
    // 快递查询
    'EXPRESS_APP_KEY' => '你的快递 APPKEY',
    'EXPRESS_QUERY_URL' => 'http://v.juhe.cn/exp/index', //快递单号查询
    'EXPRESS_COM_URL' => 'http://v.juhe.cn/exp/com', //快递公司查询
    // 发短信
    'SEND_SMS_KEY' => '你的短信接口 APPKEY',
    'SEND_SMS_URL' => 'http://v.juhe.cn/sms/send',
    // 核名
    'COMPANY_KEY' => '核名 APPKEY',
    'COMPANY_URL' => 'http://eci.yjapi.com/ECIFast/Search',
    //数据库配置信息
    'DB_TYPE'   => 'mysql', // 数据库类型
    'DB_HOST'   => 'localhost', // 服务器地址
    'DB_NAME'   => '你的数据库名', // 数据库名
    'DB_USER'   => '你的数据库用户名', // 用户名
    'DB_PWD'    => '密码', // 密码
    'DB_PORT'   => 3306, // 端口
    'DB_PREFIX' => 'pre_', // 数据库表前缀 
    'DB_CHARSET'=> 'utf8', // 字符集
);

设置数据库
为了防止恶意用户利用暴露在外的短信接口捣乱,需要对每个手机号码的行为进行记录。例如:
向某个手机号码发送短信验证码后, 60 秒内不能再次发送
必须在 1 小时内填写短信验证码,否则会过期
避免 ajax 请求地址被机器人程序利用,在表单里要使用图片验证码才能提交数据

关于“表单验证码”我们后面代码会说明,这里先创建表结构如下,用于记录短信发送记录:

CREATE TABLE `pre_smsrecord` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `mobile` varchar(11) NOT NULL DEFAULT '',
  `tpl_id` int(11) NOT NULL,
  `code` int(6) NOT NULL,
  `time` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=M

mobile手机号码
tpl_id是在网站后台添加并通过审核的短信模板
code是发送的验证码(一般是4位或6位)
time是发送时间戳

直接下载sql进行还原:在本项目的 GitHub 地址上也可以直接从 /Pubic
目录找到 sql 文件,你可以直接把它还原你的 MySQL 上。

表单验证码的实现
最终效果如下:

验证码

因为三个功能都需要表单验证码,所以首先实现它。
打开 /Home/View/Index_index.html
,注意里面图片验证码 img 标签,以及对应的 javascript

<p>
    (通用)输入验证码 <input type="text" name="verify" id="verify">
    <img id="verify-img" src="/?m=Home&c=Index&a=verify" alt="">
    <a id="btn-refresh-verify" href="javascript:;" title="">刷新</a>
</p>
<script type="text/javascript" charset="utf-8">
jQuery(document).ready(function($) {
    // 刷新验证码按钮
    $("#btn-refresh-verify").click(function(event) {
    
        $("#verify-img").attr('src', '/?m=Home&c=Index&a=verify' + "&time=" + new Date().getTime());
    });
});
</script>

对应的后端代码在 /Home/Controller/IndexController.class.php

/**
* +--------------------------------------------------------------------------
* 生成验证码
*
* +--------------------------------------------------------------------------
*/
public function verify(){
    $Verify = new \Think\Verify();
    $Verify->entry();
}
/**
* +--------------------------------------------------------------------------
* 检查验证码
*
* @param string $code 输入的验证码
* @return boolean
* +--------------------------------------------------------------------------
*/
protected function check_verify($code){
    $verify = new \Think\Verify();
    return $verify->check($code);
}

通用的 Curl 方法,用来向第三方网站的 API 发起请求并获取返回值
因为 3 个功能实际上都是通过网络来请求一个第三方网站的 API 接口地址,因此可以统一成一个通用的方法。代码如下,可以传入三个变量,分别为 :url、参数数组、请求方式(是否是post,默认为0),返回一个 json 格式的数据。

/**
* +--------------------------------------------------------------------------
* 通用的“聚合数据”请求接口,返回JSON数据
*
* @param string $url 接口地址
* @param array $params 传递的参数
* @param int $ispost 是否以POST提交,默认GET
* @return json
* +--------------------------------------------------------------------------
*/
public function juhecurl($url,$params=false,$ispost=0){
    $httpInfo = array();
    $ch = curl_init();
    curl_setopt( $ch, CURLOPT_HTTP_VERSION , CURL_HTTP_VERSION_1_1 );
    curl_setopt( $ch, CURLOPT_USERAGENT , 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22' );
    curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT , 30 );
    curl_setopt( $ch, CURLOPT_TIMEOUT , 30);
    curl_setopt( $ch, CURLOPT_RETURNTRANSFER , true );
    if( $ispost )
    {
        curl_setopt( $ch , CURLOPT_POST , true );
        curl_setopt( $ch , CURLOPT_POSTFIELDS , $params );
        curl_setopt( $ch , CURLOPT_URL , $url );
    }
    else
    {
        if($params){
            curl_setopt( $ch , CURLOPT_URL , $url.'?'.$params );
        }else{
            curl_setopt( $ch , CURLOPT_URL , $url);
        }
    }
    $response = curl_exec( $ch );
    if ($response === FALSE) {
          //echo "cURL Error: " . curl_error($ch);
        return false;
    }
    $httpCode = curl_getinfo( $ch , CURLINFO_HTTP_CODE );
    $httpInfo = array_merge( $httpInfo , curl_getinfo( $ch ) );
    curl_close( $ch );
    return $response;
}

后面我们获取快递数据、发送短信、查询企业名称,都可以调用这个通用的方法。
获取快递数据列表的实现
最终效果如下:

快递查询

打开 /Home/View/Index_index.html

<h1>获取快递数据</h1>
<div id="express-module">
    <p>
        选择公司
        <select name="express-company" id="express-company">
            <option value="sf">顺丰</option>
            <option value="sto">申通</option>
            <option value="yt">圆通</option>
            <option value="yd">韵达</option>
            <option value="tt">天天</option>
            <option value="ems">EMS</option>
            <option value="zto">中通</option>
            <option value="ht">汇通</option>
        </select>
    </p>
    <p> 
        输入单号 <input type="text" name="express-number" id="express-number"> 
    </p>
    <p>
        <button id="btn-query-express" type="button" class="btn btn-default">查询快递</button> 
    </p>
    
    <p>返回结果:</p>
    <p id="reason" style="color:#FF0000"></p>
    
    <p>快件动态:</p>
    <ul id="express-result">
        
    </ul>
</div>    
<!-- 引入jquery库 -->
<script src="__PUBLIC__/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript" charset="utf-8">
jQuery(document).ready(function($) {
    //点击快递查询按钮
    $("#btn-query-express").click(function(event) {
        $("#reason").html("");
        // 更新验证码
        $("#verify-img").attr('src', '/?m=Home&c=Index&a=verify' + "&time=" + new Date().getTime());
        $.getJSON(
            '/?m=Home&c=Index&a=getExpressData', 
            {
                company: $("#express-company").val(),
                number: $("#express-number").val(),
                verify: $("#verify").val(),
            }, 
            function(json, textStatus) {
                if(json['resultcode'] == 200){
                    var result_list = json['result']['list'];
                    $("#express-result").html("");
                    for(var i = 0, l = result_list.length; i < l; i++) {
                        $("#express-result").append("<li>" + result_list[i]['datetime'] + "," + result_list[i]['remark'] + "," +result_list[i]['zone'] + "</li>");
                    }
                }
                $("#reason").html(json['reason']);
        });
    });
});
</script>

对应的后端代码为如下,特别注意,你要把 $content = $this->juhecurl(C("EXPRESS_QUERY_URL"), $params, 1);
这段的注释去掉(因为我开发的时候查询余额不足,所以使用了一个写死的数组来让程序能正常运行)

/** 
* +--------------------------------------------------------------------------
* 获取快递数据
*
* @param string $get.company 快递公司代码
* @param string $get.number 快递单号
* @return json
* +--------------------------------------------------------------------------
*/
public function getExpressData(){
    // 传入 get 参数,包括公司代号、快递单号、验证码
    $com    = I("get.company");
    $no     = I("get.number");
    $verify = I("get.verify");
    // 处理验证码
    if ( !$this->check_verify($verify) ) {
        $content = array('resultcode'=>1000, 'reason'=>'验证码填写错误');
        echo json_encode($content);
        exit();
    }
    // 处理机器人程序刷接口(目前通过IP判断)
    $ip = get_client_ip(0, true);
    $Record = M("expressrecord");
    $express_record = $Record->where("ip='" . $ip . "'")->find();
    if( $express_record && ( (time() - $express_record['time']) < 60 ) ){
        echo json_encode(array('reason'=>'60秒内只能查询一次'));
        exit();
    }
    if ( $com && $no ) {
        $params = array(
            'key' => C("EXPRESS_APP_KEY"),
            'com'  => $com,
            'no' => $no
        );
        // 开发测试阶段直接返回值,不请求 API
        // $content = $this->juhecurl(C("EXPRESS_QUERY_URL"), $params, 1);
        $content = array('resultcode'=>200, 'reason'=>'查询成功', 'result'=>array('list'=>array()));
        // 删除旧记录(如果有),然后添加新的记录
        $Record->where("ip='" . $ip . "'")->delete();
        $data = array(
            'ip' => $ip,
            'time'=>time()
        );
        $Record->add($data);
        //$returnArray = json_decode($content,true);
        echo json_encode($content, true);
    }
}

短信验证码的发送和检验

短信验证码

废话不多说,前端html直接上代码。这里实际上有两个动作,一个是“给我手机号码 xxxxx 发个验证码”,另一个是“我已经收到了,并填写了,请看我填写的验证码对不对”。

<h1>发送短信验证码与检查</h1>
<div id="sms-module">
    <p>
        短信模板:
        <select name="send-sms-tplid" id="send-sms-tplid">
            <option value="5596">申请注册</option>
            <option value="5602">申请找回密码</option>
            <option value="5603">在线核名</option>
        </select>
    </p>
    
    <p>
        手机号码:<input type="text" name="send-sms-mobile" id="send-sms-mobile">
    </p>
    
    <p>
        输入手机验证码:<input type="text" name="send-sms-code" id="send-sms-code">
        <span id="sms-count-down"></span>
        <button id="btn-send-sms" type="button" class="btn btn-default">发送验证码</button>
    </p>
    
    <p>
        <button id="btn-check-sms" type="button" class="btn btn-default">提交手机验证码</button>
    </p>
</div>
<script type="text/javascript" charset="utf-8">
/**
* 发送短信验证码后,60秒倒计时
*/
var seconds_left = 60;
function sms_count_down(){
    if(seconds_left > 0){
        seconds_left = seconds_left-1;
        //var b=new Date();
        
        document.getElementById("sms-count-down").innerHTML = seconds_left + "秒";
        setTimeout("sms_count_down()",1000);
    } else {
        //根据 http://stackoverflow.com/questions/7526601/setattributedisabled-false-changes-editable-attribute-to-false
        // 不能为 setAttribute 设置任何值,都会变成 ”disabled“,要使用 removeAttribute
        document.getElementById("btn-send-sms").removeAttribute("disabled");
        document.getElementById("btn-send-sms").innerHTML = "重新发送";
        document.getElementById("sms-count-down").innerHTML = "";
    }
}
jQuery(document).ready(function($) {
//发送短信
    $("#btn-send-sms").click(function(event) {
        $("#reason").html("");
        $.getJSON(
            '/?m=Home&c=Index&a=sendSMS', 
            {
                tplid: $("#send-sms-tplid").val(),
                mobile: $("#send-sms-mobile").val(),
            }, 
            function(json, textStatus) {
                $("#reason").html(json['reason']);
                var error_code = json['error_code'];
                if(error_code == 0){
                    // 测试阶段,不禁用,可检查 60 秒重复发送
                    //$("#btn-send-sms").attr("disabled", true);
                    //开始倒计时
                    sms_count_down();
                }else{
                    $("#btn-send-sms").html("重新发送");
                }
    
        });
    });
    //检查短信验证码
    $("#btn-check-sms").click(function(event) {
        $("#reason").html("");
        // 更新验证码
        $("#verify-img").attr('src', '/?m=Home&c=Index&a=verify' + "&time=" + new Date().getTime());
        $.getJSON(
            '/?m=Home&c=Index&a=checkSmsCode', 
            {
                tplid: $("#send-sms-tplid").val(),
                mobile: $("#send-sms-mobile").val(),
                code: $("#send-sms-code").val(),
                verify: $("#verify").val(),
            }, 
            function(json, textStatus) {
                $("#reason").html(json['reason']);
    
        });
    });
    
});

同样因为有两个动作,后端会稍微复杂一点点

/**
* +--------------------------------------------------------------------------
* 请求发送短信接口,60秒后才能重新发送
*
* @param int $get.tplid 短信模板id
* @param string $get.mobile 手机号码
* @return json
* +--------------------------------------------------------------------------
*/
public function sendSMS(){
    $tpl_id = I("get.tplid"); // 短信模板id:注册 5596 找回密码 5602 在线核名 5603
    $mobile = I("get.mobile"); // 手机号码
    // 检查数据库记录 ,是否在 60 秒内已经发送过一次
    $Record = M("smsrecord");
    $where = array(
        'mobile' => $mobile,
        'tpl_id' => $tpl_id,
    );
    $sms_record = $Record->where($where)->find();
    if( $sms_record && ( (time() - $sms_record['time']) < 60 ) ){
        echo json_encode(array('reason'=>'60秒内不能多次发送'));
        exit();
    }
    // 如果60秒内没有发过,则发送验证码短信(6位随机数字)
    $code = mt_rand(100000, 999999);
    $smsConf = array(
        'key'   => C("SEND_SMS_KEY"), //您申请的APPKEY
        'mobile'    => $mobile, //接受短信的用户手机号码
        'tpl_id'    => $tpl_id, //您申请的短信模板ID,根据实际情况修改
        'tpl_value' =>'#code#=' . $code //您设置的模板变量,根据实际情况修改 '#code#=1234&#company#=聚合数据'
    );
     
    //测试阶段,不发短信,直接设置一个“发送成功” json 字符串
    $content = $this->juhecurl(C("SEND_SMS_URL") ,$smsConf, 1); //请求发送短信
    //$content = json_encode(array('error_code'=>0, 'reason'=>'发送成功'));
    if($content){
        $result = json_decode($content,true);
        $error_code = $result['error_code'];
        if($error_code == 0){
            // 状态为0,说明短信发送成功
            // 数据库存储发送记录,用于处理倒计时和输入验证,首先要删除旧记录
            $Record->where("mobile=" . $mobile)->delete();
                $data = array(
                    'mobile' => $mobile,
                    'tpl_id'=> $tpl_id,
                    'code'=>$code,
                    'time'=>time()
                );
                $Record->data($data)->add();
            //echo "短信发送成功,短信ID:".$result['result']['sid'];
        }else{
            //状态非0,说明失败
            //echo "短信发送失败(".$error_code."):".$msg;
        }
    }else{
        //返回内容异常,以下可根据业务逻辑自行修改
        //$result['reason'] = '短信发送失败';
    }
    echo $content;
}
/**
* +--------------------------------------------------------------------------
* 检查填写的手机验证码是否填写正确
* 可以添加更多字段改造成注册、登录等表单
*
* @param string $get.verify 验证码
* @param string $get.mobile 手机号码
* @param int $get.tplid 短信模板ID
* @param int $get.code 手机接收到的验证码
* +--------------------------------------------------------------------------
*/
public function checkSmsCode(){
    $verify = I("get.verify");
    $tpl_id = I("get.tplid"); // 短信模板id:注册 5596 找回密码 5602 在线核名 5603
    $mobile = I("get.mobile"); // 手机号码
    $code = I("get.code"); // 手机收到的验证码
    if(!$this->check_verify($verify)){
        $content = array('resultcode'=>1000, 'reason'=>'验证码填写错误');
        echo json_encode($content);
        exit();
    }
    // 检查数据库记录,输入的手机验证码是否和之前通过短信 API 发送到手机的一致
    $Record = M("smsrecord");
    $where = array(
        'mobile' => $mobile,
        'tpl_id' => $tpl_id,
        'code' => $code,
    );
    $sms_record = $Record->where($where)->find();
    if($sms_record){
        echo json_encode(array('reason'=>'短信验证码核对成功'));
        // 处理后面的程序(如继续登录、注册等)
    }else{
        echo json_encode(array('reason'=>'短信验证码错误'));
    }
}

最后是企业核名
因为这个接口本来只提供了每次查询一个关键词,而朋友的网站要求能每次查询用“,”分隔的多个关键词,因此需要对提交的数据和返回到前端的进行一番处理(循环处理多个列表)。
[图片上传中。。。(22)]
前端代码比较简单

<h1>企业核名</h1>
<div id="company-module">
    <p>
        省份:上海
        <input type="hidden" name="company-province" id="company-province" value="SH">
    </p>
    <p>
        <input type="text" name="company-name" id="company-name">
    </p>
</div>
<button id="btn-company" type="button" class="btn btn-default">企业核名</button>
<p>公司查询列表:</p>
<ul id="company-result">
    
</ul>
<javascript 略……
//企业核名(可输入多个以逗号分隔的名称来多次查询)
$("#btn-company").click(function(event) {
    $("#reason").html("");
    $("#company-result").html("");
    // 更新验证码
    $("#verify-img").attr('src', '/?m=Home&c=Index&a=verify' + "&time=" + new Date().getTime());
    $.getJSON(
        '/?m=Home&c=Index&a=getCompanyName', 
        {
            province: $("#company-province").val(),
            companyName: $("#company-name").val(),
            verify: $("#verify").val(),
        }, 
        function(json, textStatus) {
            if(json['reason']){
                $("#reason").html(json['reason']);
            } else {
                //console.log(json);
                var json_list = JSON.parse(json);
                if (json_list.length > 0){
                    for(i in json_list){
                        var result_list = json_list[i].Result;
                        if (result_list.length > 0){
                            for(j in result_list){
                                //console.log(result_list[j]);
                                $("#company-result").append("<li> 名称:" + result_list[j].Name + ", 法人:" + result_list[j].OperName + ", 状态:" + result_list[j].Status + "</li>");
                            }
                        }
                    }
                }
            }
    });
});
</javascript>

后端代码

/** 
* +--------------------------------------------------------------------------
* 企业核名
* 该接口 http://eci.yjapi.com/ECIFast/Search 仅支持 GET 方式,因此 $param 为字符串形式
*
* @param string $get.province 省份
* @param string $get.companyName 公司名
* @return json
* +--------------------------------------------------------------------------
*/
public function getCompanyName(){
    // 传入 get 参数
    $province                = I("get.province");
    $companyName    = I("get.companyName");
    $verify         = I("get.verify");
    // 处理验证码
    if ( !$this->check_verify($verify) ) {
        $content = array('resultcode'=>1000, 'reason'=>'验证码填写错误');
        echo json_encode($content);
        exit();
    }
    // 处理机器人程序刷接口(目前通过IP判断)
    $ip = get_client_ip(0, true);
    $Record = M("companyrecord");
    $company_record = $Record->where("ip='" . $ip . "'")->find();
    // if( $company_record && ( (time() - $company_record['time']) < 60 ) ){
    //     echo json_encode(array('reason'=>'60秒内只能查询一次企业名称'));
    //     exit();
    // }
    $resultArray = array();
    if ( $province && $companyName ) {
        // 删除旧记录(如果有),然后添加新的记录
        $Record->where("ip='" . $ip . "'")->delete();
        // 循环处理多个公司名
        $companies = explode(",", $companyName);
        foreach ($companies as $key => $value) {
            $params = "key=" . C("COMPANY_KEY") . "&province={$province}&companyName={$value}";
            // 开发测试阶段直接返回值,不请求 API
            $content = $this->juhecurl(C("COMPANY_URL"), $params, 0);
            $returnArray = json_decode($content,true);
            // 循环插入新的结果
            $resultArray[] = $returnArray;
            //$content = array('resultcode'=>200, 'reason'=>'查询成功', 'result'=>array('list'=>array()));
        }
        $data = array(
            'ip' => $ip,
            'time'=>time()
        );
        $Record->add($data);
        $content = json_encode($resultArray, true);
        echo json_encode($content, true);
    }
}

结束
至此三个功能都已经完成了,但是在防止恶意用户利用接口干坏事的策略上,还可以更进一步。例如
必须要注册用户才能发送请求
手机号码每天只能限制发送有限的验证码(因为目前即使每分钟发送一次,一天下来也比较可观了)
手机号码注册后,再次请求发送验证码时,只能发给“已有”的手机号码数据表里的手机号码,而不能把“找回密码”发给一个还没注册的人。

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,364评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,579评论 18 139
  • 我记得在《后会无期》里有这样一句:听过很多大道理,依旧过不好这一生。过不好这一生是很正常不过的。因为道理你只听过,...
    正午阅读 262评论 0 1
  • 今天是我正念饮食的第四次被教练 回顾了上周,我觉得自己做到了预定的70%,还有30%没有做到,是因为外出吃饭啊,有...
    齐文系统排列阅读 556评论 1 3
  • 文|你这磨人的小妖精 昨晚高中好友约我吃饭。不知道哪来的突发奇想,就说一起去母校看看。带着兴致冲冲和满心澎湃前往,...
    小妖的幺阅读 1,814评论 2 7