[网络篇]ESP8266-SDK教程(六)之网页配置Wi-Fi名称和密码

这个周末有点忙,明天就是新的一周了,今晚更新一下文章!在上篇文章中有一点小小的历史遗留问题,不知道大家有没有自己实现出来,今天就给大家说一说网页配置Wi-Fi是怎么实现的,最近也是比较忙,手头有点小项目,今天抽点时间给大家讲一下~

开始之前,照例我们还是先了解一下基础知识吧,既然这里我们是用网页就配置,那么我们就有必要了解一下浏览器与Web Server之间是怎样通信的,相信每个人都有过在地址栏输入网址的时候,而且会经常看见"http"、"https"等字样,那么你有没有深入去了解一下这几个字母是什么意思呢?为什么网址的前面会加入这几个字母?可能很多人都是知道有,但是具体是什么作用没好好去了解,那么这里就简单给大家科普一下,毕竟我也不是专业的对这块知识也是停留在知道了解懂点的水平上。

首先我们需要先知道"http"、"https"是什么意思,戳卡片了解一下~

http_百度百科​baike.baidu.com

https_百度百科​baike.baidu.com
图标

看完后是不是有点恍然大悟了?是不是觉得也没那么高大上了?其实,就是一种传输协议,不过传输的内容多以网页居多,http是在TCP/IP传输层之上的应用层协议,所以最根本的还是回到了TCP/IP通信,只不过http做了很多规范,包括请求格式,响应格式,状态码等等,http协议有一套很完整的规范,大家可以在这个规范之下传输数据,我们本篇文章虽然写着是网页配置,但是在界面之下的数据都是在http规范之下进行传输的,然后我们在Web Server(ESP8266)端进行数据解析,最后得到我们想要的信息。

先来简单看一下流程吧,做了一个草图,PS水平不佳,够用水平~

image

流程就是这个样子,通过网页发送SSID和PWD给ESP8266,ESP8266解析以后得到SSID和PWD去连接Wi-Fi,流程没多少东西,下面我们来看每一步是如何实现的!

首先是我们需要打开这个网页,但是我们该怎么样打开呢?网址是什么呢?可能大家会有这样的疑问,但是你有没有配置过家里的路由器呢?如果有的话,其实跟那个是一样的道理,没有配置的过的,我就给大家说一下,要知道的是在我们的ESP8266连接上路由器之前,我们是不可能在路由器这个局域网之下找到这个设备的,所以我们去访问路由器下的子设备是不可能实现的,所以ESP8266应该是在AP模式,我们需要用手机或者PC去连接ESP8266,然后我们去访问ESP8266在AP模式下的IP地址才能打开这个可以配置的网页,就像我们家里的路由器,有一个固定的IP是去设置一些路由器参数的,这里原理是相同的。

然后我们打开这个网页,但是这个网页是保存在哪呢?其实就像你家里的路由器一样,这个配置网页都是保存在设备当中的,可能家里的路由器可存储空间比较大,还跑着OpenWRT系统,但是我们ESP8266是一样可以去实现的,我们需要将这个写好的网页,保存到ESP8266的flash当中,当ESP8266收到http请求时,我们再将这个网页从flash中读出来,发送给浏览器,可能有些人觉得有点不可思议,其实网页本身就是一个文件,flash就是存储文件的,我们既然可以写固件,那么同样可以写很多别的东西,此时ESP8266就是一个很小的Web Server,处理来自浏览器的http请求,然后按照一定格式返回具体的网页,或者其他数据,这些都是通过TCP传输的。

那么我们了解了整个流程,也知道了网页是在哪保存着,那我们现在就却一个网页了,网页不要写的很复杂,因为ESP8266的flash是有限的,我们不能占用太大的地方,某些地方还是要存储我们编译好的程序的,大家应该也会写一点简单的网页吧?HTML是超文本标记语言,通过一些标签来实现特定的显示内容或者格式,不懂的可以稍微看一下,或者想实现什么功能就是百度一下,当然我这里嘛,就是比较熟悉了,因为从初中开始我就对做一个个人主页很感兴趣,所以没事也会看看这方面的知识,大家先看看这个界面吧,我也是简单一写。

image

<figcaption style="margin-top: 0.66667em; padding: 0px 1em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">网页配置ESP8266 WiFi密码</figcaption>

就一个很简单的表格,填完以后,按下按键,表格中的内容就会以http协议的格式发送给ESP8266,这不是重要的,我们看一下ESP8266端是如何处理我们通过网页发送的数据。

直接上代码吧~

/*********************
 *      DEFINES
 *********************/
#define INDEX_SIZE  4410
#define WEBCONFIG_SIZE  4526
#define WIFIDONE_SIZE   4266

/**********************
 *      TYPEDEFS
 **********************/
static struct espconn webserver_espconn;
static esp_tcp webserver_esptcp;
/**********************
 *  STATIC PROTOTYPES
 **********************/
static void webconfig_get_wifi_ssid_pwd(char* urlparam);
static void softAP_init(void);
static bool parse_url(char *precv, URL_Frame *purl_frame);
static void webserver_recv(void *arg, char *pusrdata, unsigned short length);
static void data_send(void *arg, bool responseOK, char *psend);
static bool parse_url(char *precv, URL_Frame *purl_frame);
static bool save_data(char *precv, uint16 length);
static bool check_data(char *precv, uint16 length);
static void webserver_recon(void *arg, sint8 err);
static void webserver_discon(void *arg);
static void webserver_listen(void *arg);
/************************
 *   STATIC VARIABLES   *
 ************************/
static char *precvbuffer;
static uint32 dat_sumlength = 0;

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/
void ICACHE_FLASH_ATTR
user_webserver_init(uint32 port){

    softAP_init();

    webserver_espconn.type = ESPCONN_TCP;
    webserver_espconn.state = ESPCONN_NONE;
    webserver_espconn.proto.tcp = &webserver_esptcp;
    webserver_espconn.proto.tcp->local_port = port;
    espconn_regist_connectcb(&webserver_espconn, webserver_listen);
    espconn_regist_reconcb(&webserver_espconn,webserver_recon);

    espconn_accept(&webserver_espconn);
}

/**********************
 *   STATIC FUNCTIONS
 **********************/
/*
 * softAP模式初始化代码
 */
static void ICACHE_FLASH_ATTR
softAP_init(void){
    struct softap_config soft_ap_Config;

    wifi_set_opmode_current(SOFTAP_MODE);//设置为AP模式,不保存到flash
//  wifi_set_opmode(SOFTAP_MODE);//设置为AP模式,并保存到flash

    soft_ap_Config.ssid_len = 14;//热点名称长度,与你实际的名称长度一致就好
    os_strcpy(soft_ap_Config.ssid,"zhihu-IAMLIUBO");//实际热点名称设置,可以根据你的需要来
    os_strcpy(soft_ap_Config.password,"imliubo123");//热点密码设置
    soft_ap_Config.authmode = AUTH_WPA2_PSK;//设置权限模式,AUTH_WPA2_PSK这是一种加密算法
    soft_ap_Config.beacon_interval = 100;//信标间隔,默认为100
    soft_ap_Config.channel = 1;//信道,共支持1~13个信道
    soft_ap_Config.max_connection = 2;//最大连接数量,最大支持四个,默认四个
    soft_ap_Config.ssid_hidden = 0;//隐藏SSID,0:不隐藏  1:隐藏

    wifi_softap_set_config_current(&soft_ap_Config);//设置 Wi-Fi SoftAP 接口配置,不保存到 Flash
//  wifi_softap_set_config(&soft_ap_Config);//设置 Wi-Fi SoftAP 接口配置,保存到 Flash

    os_printf("\r\nSSID: zhihu-IAMLIUBO\r\nPWD: imliubo123\r\n");
}

static void ICACHE_FLASH_ATTR
webserver_recv(void *arg, char *pusrdata, unsigned short length)
{
    URL_Frame *pURL_Frame = NULL;
    char *pParseBuffer = NULL;
    char *html = NULL;
    SpiFlashOpResult ret = 0;

    os_printf("\r\n\r\nlength:%d\r\n", length);
    os_printf("recv:%s", pusrdata);

    pURL_Frame = (URL_Frame *)os_zalloc(sizeof(URL_Frame));

    parse_url(pusrdata, pURL_Frame);
    os_printf("\r\nType[%d]\r\n", pURL_Frame->Type);
    os_printf("pSelect[%s]\r\n", pURL_Frame->pSelect);
    os_printf("pCommand[%s]\r\n", pURL_Frame->pCommand);
    os_printf("pFilename[%s]\r\n", pURL_Frame->pFilename);

    switch (pURL_Frame->Type) {
        case GET:
            os_printf("We have a GET request.\n");
                if(pURL_Frame->pFilename[0] == 0){
                    html = (char *)os_zalloc(INDEX_SIZE);
                    if(html == NULL){
                        os_printf("os_zalloc error!\r\n");
                        goto _temp_exit;
                    }
                    // Flash read/write has to be aligned to the 4-bytes boundary
                    ret = spi_flash_read(508*4096, (uint32 *)html, INDEX_SIZE);  // start address:0x10000 + 0xC0000
                    if(ret != SPI_FLASH_RESULT_OK){
                        os_printf("spi_flash_read err:%d\r\n", ret);
                        os_free(html);
                        html = NULL;
                        goto _temp_exit;
                    }
                    html[INDEX_SIZE] = 0;   // put 0 to the end
                    data_send(arg, true, html);
                    os_free(html);
                    html = NULL;
                }
                if(strncmp(pURL_Frame->pFilename, "WebConfig.html", strlen("WebConfig.html")) == 0){
                    html = (char *)os_zalloc(WEBCONFIG_SIZE);
                    if(html == NULL){
                        os_printf("os_zalloc error!\r\n");
                        goto _temp_exit;
                    }
                    // Flash read/write has to be aligned to the 4-bytes boundary
                    ret = spi_flash_read(510*4096, (uint32 *)html, WEBCONFIG_SIZE);  // start address:0x10000 + 0xC0000
                    if(ret != SPI_FLASH_RESULT_OK){
                        os_printf("spi_flash_read err:%d\r\n", ret);
                        os_free(html);
                        html = NULL;
                        goto _temp_exit;
                    }
                    html[WEBCONFIG_SIZE] = 0;   // put 0 to the end
                    data_send(arg, true, html);
                    os_free(html);
                    html = NULL;
                }
            break;

        case POST:
            os_printf("We have a POST request.\r\n");
            if(strncmp(pURL_Frame->pCommand, "connect-wifi", strlen("connect-wifi")) == 0){
                os_printf("connect wifi\r\n");
                webconfig_get_wifi_ssid_pwd(pusrdata);
                html = (char *)os_zalloc(WIFIDONE_SIZE);
                if(html == NULL){
                    os_printf("os_zalloc error!\r\n");
                    goto _temp_exit;
                }
                ret = spi_flash_read(512*4096, (uint32 *)html, WIFIDONE_SIZE);  // start address:0x10000 + 0xC0000
                if(ret != SPI_FLASH_RESULT_OK){
                    os_printf("spi_flash_read err:%d\r\n", ret);
                    os_free(html);
                    html = NULL;
                    goto _temp_exit;
                }
                html[WIFIDONE_SIZE] = 0;   // put 0 to the end
                data_send(arg, true, html);
                os_free(html);
                html = NULL;
            }
            break;
    }
    _temp_exit:
        ;
    if(pURL_Frame != NULL){
        os_free(pURL_Frame);
        pURL_Frame = NULL;
    }

}

static void ICACHE_FLASH_ATTR
webconfig_get_wifi_ssid_pwd(char* urlparam)
{
    char *p = NULL, *q = NULL;
    char ssid[10], pass[15];

    os_memset(ssid, 0, sizeof(ssid));
    os_memset(pass, 0, sizeof(pass));

    p = (char *)os_strstr(urlparam, "SSID=");
    q = (char *)os_strstr(urlparam, "PASSWORD=");
    if ( p == NULL || q == NULL ){
        return;
    }
    os_memcpy(ssid, p + 5, q - p - 6);
    os_memcpy(pass, q + 9, os_strlen(urlparam) - (q - urlparam) - 9);
    os_printf("ssid[%s]pass[%s]\r\n", ssid, pass);

    wifi_set_opmode(STATION_MODE);
    struct station_config stConf;
    stConf.bssid_set = 0;
    os_memset(&stConf.ssid, 0, sizeof(stConf.ssid));
    os_memset(&stConf.password, 0, sizeof(stConf.password));

    os_memcpy(&stConf.ssid, ssid, os_strlen(ssid));
    os_memcpy(&stConf.password, pass, os_strlen(pass));

    wifi_station_set_config(&stConf);
    //重启
    system_restart();
}
/******************************************************************************
 * FunctionName : parse_url
 * Description  : parse the received data from the server
 * Parameters   : precv -- the received data
 *                purl_frame -- the result of parsing the url
 * Returns      : none
*******************************************************************************/
static bool ICACHE_FLASH_ATTR
parse_url(char *precv, URL_Frame *purl_frame)
{
    char *str = NULL;
    uint8 length = 0;
    char *pbuffer = NULL;
    char *pbufer = NULL;

    if (purl_frame == NULL || precv == NULL) {
        return false;
    }

    pbuffer = (char *)os_strstr(precv, "Host:");

    if (pbuffer != NULL) {
        length = pbuffer - precv;
        pbufer = (char *)os_zalloc(length + 1);
        pbuffer = pbufer;
        os_memcpy(pbuffer, precv, length);
        os_memset(purl_frame->pSelect, 0, URLSize);
        os_memset(purl_frame->pCommand, 0, URLSize);
        os_memset(purl_frame->pFilename, 0, URLSize);

        if (os_strncmp(pbuffer, "GET ", 4) == 0) {
            purl_frame->Type = GET;
            pbuffer += 4;
        } else if (os_strncmp(pbuffer, "POST ", 5) == 0) {
            purl_frame->Type = POST;
            pbuffer += 5;
        }else{
            return false;
        }

        pbuffer ++;
        str = (char *)os_strstr(pbuffer, "HTTP");

        if (str != NULL) {
            length = str - pbuffer - 1;
            os_memcpy(purl_frame->pFilename, pbuffer, length);
        }

        os_free(pbufer);
    }

    pbuffer = (char *)os_strstr(precv, "SSID");
    if (pbuffer != NULL) {
        purl_frame->Type = POST;
        os_memcpy(purl_frame->pCommand, "connect-wifi", strlen("connect-wifi"));
        os_free(pbufer);
    }

}
/******************************************************************************
 * FunctionName : data_send
 * Description  : processing the data as http format and send to the client or server
 * Parameters   : arg -- argument to set for client or server
 *                responseOK -- true or false
 *                psend -- The send data
 * Returns      :
*******************************************************************************/
static void ICACHE_FLASH_ATTR
data_send(void *arg, bool responseOK, char *psend)
{
    uint16 length = 0;
    char *pbuf = NULL;
    char httphead[256];
    struct espconn *ptrespconn = arg;
    os_memset(httphead, 0, 256);

    if (responseOK) {
        os_sprintf(httphead,
                   "HTTP/1.0 200 OK\r\nContent-Length: %d\r\nServer: lwIP/1.4.0\r\n",
                   psend ? os_strlen(psend) : 0);

        if (psend) {
            os_sprintf(httphead + os_strlen(httphead),
                       "Content-type: text/html; charset=utf-8\r\nPragma: no-cache\r\n\r\n");
            length = os_strlen(httphead) + os_strlen(psend);
            pbuf = (char *)os_zalloc(length + 1);
            os_memcpy(pbuf, httphead, os_strlen(httphead));
            os_memcpy(pbuf + os_strlen(httphead), psend, os_strlen(psend));
        } else {
            os_sprintf(httphead + os_strlen(httphead), "\n");
            length = os_strlen(httphead);
        }
    } else {
        os_sprintf(httphead, "HTTP/1.0 400 BadRequest\r\nContent-Length: 0\r\nServer: lwIP/1.4.0\r\n\n");
        length = os_strlen(httphead);
    }

    if (psend) {
        espconn_sent(ptrespconn, pbuf, length);
    } else {
        espconn_sent(ptrespconn, httphead, length);
    }

    if (pbuf) {
        os_free(pbuf);
        pbuf = NULL;
    }
}

其中webserver_recv函数就是处理浏览器发来的各种http请求,我这里实际写了三个页面:首页、配置页面、配置完成页面,所以处理的有点多,spi_flash_read函数是将保存在flash中的网页读出来,可以看出我是从三个不同的地址读出来的网页,这个地址是根据你将网页写在了什么位置而去计算的,可以看一下我将三个网页烧录在了什么位置:

image

其中makingfun.html就是首页,我是烧录在了0x1FC000地址,那在代码中是从哪一个地方读出的呢?

spi_flash_read(508*4096, (uint32 *)html, INDEX_SIZE); 

就是508x4096这个地址,0x1FC000是508x4096结果的十六进制,在ESP8266 flash操作中是4字节对齐的,一个扇区4KB,每次擦写都需要整个扇区去操作。我们后面再详细说一下关于flash操作的一些注意事项。

parse_url函数是解析http请求中携带的URL参数、请求方法、请求的文件名称,主要使用的是C库中的字符串处理函数,然后根据http请求格式中固定的字段去解析出我们实际传进来的参数。

webconfig_get_wifi_ssid_pwd函数就是解析我们填在表格中的Wi-Fi名称和密码了,也是使用的C库中的字符串处理函数,其中“SSID”和“PASSWORD”是表格属性,等号后边是我们填写的内容,“&”不是我们填写的,所以计算的时候需要将它剔除掉。

最后还需要注意一点的是,这个三个宏定义:

#define INDEX_SIZE  1437
#define WEBCONFIG_SIZE  1541
#define WIFIDONE_SIZE   1293

这是我们写好的网页的实际大小,也就是我们实际写到flash当中的网页大小,这里需要根据你实际的网页大小去更改。

下面我们看一下三个页面的HTML代码:

首页代码:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
        <title>
            IAMLIUBO的神奇物联网之旅
        </title>
    </head>
    <body>
        <div align="center">
            <font>
                IAMLIUBO
            </font>
            <br/>
            <font>
                E-mail: imliubo@makingfun.xyz
            </font>
            <br/>
            <a href="https://zhuanlan.zhihu.com/imliubo-magic-IoT-Tutorial">
                IAMLIUBO的神奇物联网之旅
            </a>
            <br/>
            <p>
                欢迎关注我的知乎专栏,我会在专栏不定期分享一些文章,其中有包括物联网方面的,也有会有一些自己开发经验分享,关注专栏,与我一起进步!
                <br/>
                唯有爱与科技不可辜负。
                <br/>
                技术交流或者项目合作可以私信或者邮件联系我。
                <br/>
                点击按钮开始配网
            </p>
            <a href="WebConfig.html" text-decoration="none">
                <button formtarget="_self" style="display:block;margin:0 auto">
                    开始配网
                </button>
            </a>
        </div>
    </body>
</html>

配置网页代码:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
        <title>
            IAMLIUBO的神奇物联网之旅
        </title>
    </head>
    <body>
        <div align="center">
            <font>
                IAMLIUBO
            </font>
            <br/>
            <font>
                E-mail: imliubo@makingfun.xyz
            </font>
            <br/>
            <a href="https://zhuanlan.zhihu.com/imliubo-magic-IoT-Tutorial">
                IAMLIUBO的神奇物联网之旅
            </a>
            <br/>
        </div>
        <form action="WiFiConfig.html" enctype="application/x-www-form-urlencoded" method="post">
            <table align="center" border="0" cellspacing="10">
                <tr>
                    <td>
                        Wi-Fi名称:
                        <input name="SSID" placeholder="在这里输入Wi-Fi名称" type="text"/>
                    </td>
                </tr>
                <tr>
                    <td>
                        Wi-Fi密码:
                        <input name="PASSWORD" placeholder="在这里输入Wi-Fi密码" type="password"/>
                    </td>
                </tr>
            </table>
            <button style="display:block;margin:0 auto" type="submit" value="Submit">
                确认提交
            </button>
        </form>
    </body>
</html>

配网完成页面:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
        <title>
            IAMLIUBO的神奇物联网之旅
        </title>
    </head>
    <body>
        <div align="center">
            <font>
                IAMLIUBO
            </font>
            <br/>
            <font>
                E-mail: imliubo@makingfun.xyz
            </font>
            <br/>
            <a href="https://zhuanlan.zhihu.com/imliubo-magic-IoT-Tutorial">
                IAMLIUBO的神奇物联网之旅
            </a>
            <br/>
            <font>
                正在连接Wi-Fi,LED灯闪烁三次后连接完成!
                <br/>
                常亮表示连接失败请重新输入!
                <br/>
                <a href="WebConfig.html" text-decoration="none">
                    <button formtarget="_self" style="display:block;margin:0 auto">
                        重新配网
                    </button>
                </a>
                <br/>
                <a href="/">
                    返回首页
                </a>
            </font>
        </div>
    </body>
</html>

上个演示视频:

https://www.bilibili.com/video/av37953711​www.bilibili.com

视频可以去B站看了,后期比较长一点的视频都会放在B站上,因为知乎最长可以上传15分钟的视频,最大1G,所以有些比较长的视频就没法直接上传了,请谅解,代码稍后整理后我会上传到我的GitHub仓。

最后欢迎大家去我的仓库点个Star,您的鼓励是我最大的动力~有问题可以私信我,或者提交issues。

imliubo/makingfunxyz-esp8266​github.com


QQ交流群:592587184

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

推荐阅读更多精彩内容