微信小程序 微信授權(quán)前后端解決方案 (更新至5.10授權(quán)機制)

一游添、基本說明

微信小程序中對于用戶的登錄授權(quán)機制况褪,是非常重要的。許多的業(yè)務(wù)都必須拿到具體的微信數(shù)據(jù)才能進行渊季。我們在之前的微信小程序開發(fā)中朋蔫,因為業(yè)務(wù)比較簡單只有首頁,并且在進入小程序的時候就必須進行授權(quán)却汉,所以在操作的時候比較簡單驯妄。隨著業(yè)務(wù)的不斷增加,業(yè)務(wù)場景的增多合砂,之前的授權(quán)機制無法覆蓋所有的業(yè)務(wù)場景青扔。本次是在之前的授權(quán)機制的場景下,進行優(yōu)化和改版翩伪。前端和后臺進行配合微猖,完善微信的授權(quán)機制,達到適應(yīng)現(xiàn)有的業(yè)務(wù)缘屹。本文將講解從老版本到現(xiàn)版本的微信授權(quán)機制的改版優(yōu)化過程凛剥。
注:5月10日的授權(quán)方案可在第四部分直接查看

二、代碼說明

(1) 1.0版本微信授權(quán)

本文對具體的小程序端和后臺之間的微信授權(quán)不做具體的說明轻姿,詳情請看文檔犁珠。對于小程序我們封裝了兩個主要的工具模塊類。用戶模塊user.js,請求模塊request.js互亮。
user.js主要處理用戶的基本信息模塊犁享,包括授權(quán)管理和登錄,用戶其他數(shù)據(jù)的綁定等豹休。
var user = {
  config:{},
  userinfo:null,
  // 初始化user模塊炊昆,校驗ukey
  init(data){
    this.config = data;
    var self = this;
    wx.checkSession({
      success:function(res){
        //存在登錄狀態(tài)
        self.checkUkey();
      },
      fail:function(){
        //過期-重新登錄
        self.login();
      }
    });
  },
  // 發(fā)起微信登錄接口 獲取登錄憑證code
  login(){
    var self = this;
    wx.login({
      success:function(res){
        self.config.code = res.code;
        wx.setStorageSync(self.config.storage.code,res.code);
        self.getWXUserInfo(true);
      },
      fail:function(res){
        console.log("user login fail")
      }
    })
  },
  // 獲取用戶信息
  getWXUserInfo(isthrough){
    var self = this;
    wx.getUserInfo({
      success:function(res){
        self.userinfo = res.userInfo;
        wx.setStorageSync(self.config.storage.wxUser, res.userInfo);
        if (isthrough) {
          self.getUserUkey(res.rawData);
        }
      },
      fail:function(res){
        wx.openSetting({
          success:function(res){
            if(res.authSetting["scope.userInfo"]){
              wx.getUserInfo({
                success: res => {
                  // 可以將 res 發(fā)送給后臺解碼出 unionId
                  self.userinfo = res.userInfo;
                  wx.setStorageSync(self.config.storage.wxUser, res.userInfo);
                  if (isthrough) {
                    self.getUserUkey(res.rawData);
                  }
                }
              });
            }
          }
        })
      }
    })
  },
  // 獲取Ukey
  getUserUkey(rawData){
    var self = this;
    var data = {
      code: wx.getStorageSync(self.config.storage.code),
      rawData: rawData
    };
    wx.request({
      url:self.config.requrl+"/Wdservice/api/wxLogin",
      data: data,
      method:"GET",
      success:function(res){
        res = res.data;
        console.log(res);
        if(res.code==1){
          // 緩存Ukey          
           wx.setStorageSync(self.config.storage.ukey,res.result.ukey);

         // 緩存Ukey存儲時間
          wx.setStorageSync(self.config.storage.ukeytime,new Date().getTime());
       }
      }
    })
  },
  // 檢驗ukey是否過期
  checkUkey(){
    var ukey = wx.getStorageSync(this.config.storage.ukey);
    var ukeyTime = wx.getStorageSync(this.config.storage.ukeytime);
    var tmpTime = new Date().getTime();
    var token = wx.getStorageSync(this.config.storage.ukey_licaiyi);
    if (tmpTime - ukeyTime >= 1000 * 60 * 60 * 12 || !token){
      ukey = "";
      this.login();
    } else {
      this.getWXUserInfo(false);
    }
  }
}

module.exports = user;

request.js主要對請求的再封裝,統(tǒng)一加入ukey∫っ校可對接口統(tǒng)一管理屏积,增加擴展性。
var app = getApp();

// 打包ukey和參數(shù)
function ukeyData (data) {

  var copyData = JSON.parse(JSON.stringify(data));
  var ukey = { "ukey": wx.getStorageSync(app.globalData.config.storage.ukey) };
  var okUkeyData = Object.assign(copyData, ukey);
  return okUkeyData;
}

function post(data){

  req({
    url:data.url,
    method:"POST",
    data:ukeyData(data.data),
    succ:data.succ,
    fail:data.fail,
    complete:data.complete
  })
}

function get(data){
  req({
    url:data.url,
    method:"GET",
    data: ukeyData(data.data),
    succ:data.succ,
    fail:data.fail,
    complete:data.complete
  })
}

function req(data){
  wx.request({
    url: data.url,
    data: ukeyData(data.data),
    method: data.method, // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
    header: {
      'content-type':'application/x-www-form-urlencoded',
    }, // 設(shè)置請求的 header
    success: function(res){
      // success
      res = res.data;
      if(typeof data.succ === "function"){
        data.succ(res);
      }
    },
    fail:function(res){
      if(typeof data.fail === "function"){
        data.fail(res);
      }
    },
    complete:function(res){
      if(typeof data.complete === "function"){
        data.complete(res);
      }
    }
  })
}

const request = {
  post:post,
  get:get
}

module.exports = request;

具體使用:在app.js中引用user.js初始化該組件即可磅甩。每次程序啟動的時候會自動校驗ukey的有效性,如果沒有登錄或者ukey過期會重新登錄姥卢。
var user = require("/tools/user");
onLaunch: function () {
    // 檢測用戶
    user.init(config);
}

(2) 2.0版本微信授權(quán)

隨著業(yè)務(wù)的增加卷要,小程序添加了掃碼支付的功能。該功能在1.0版本的情況下會出現(xiàn)很重大的bug独榴。雖然在app.js中初始化了user.js組件并得到ukey等信息僧叉。但是跳轉(zhuǎn)到掃碼頁面的時候,因為登錄請求都是異步執(zhí)行的棺榔,在app.js完成授權(quán)之前瓶堕,界面上的接口已經(jīng)調(diào)用了。由于當時可能還沒有獲取到ukey導(dǎo)致界面上的接口報錯症歇,而獲取不到需要的數(shù)據(jù)郎笆,界面一片空白,又沒有刷新機制忘晤,導(dǎo)致出現(xiàn)嚴重的授權(quán)bug宛蚓。對于這個業(yè)務(wù)場景下1.0的微信授權(quán)已經(jīng)無法解決我們的問題,所以我們對user.js進行優(yōu)化设塔,以適應(yīng)該業(yè)務(wù)凄吏。
在user.js中添加登錄完成的回調(diào)succ
var user = {
  config:{},
  userinfo:null,
  init(data){
    this.config = data;
    var self = this;
    wx.checkSession({
      success:function(res){
        //存在登錄狀態(tài)
        self.checkUkey();
      },
      fail:function(){
        //過期-重新登錄
        self.login(null);
      }
    });
  },
  login(succ){
    var self = this;
    wx.login({
      success:function(res){
        self.config.code = res.code;
        wx.setStorageSync(self.config.storage.code,res.code);
        self.getWXUserInfo(true, succ);
      },
      fail:function(res){
        console.log("user login fail")
      }
    })
  },
  getWXUserInfo(isthrough, succ){
    var self = this;
    wx.getUserInfo({
      success:function(res){
        self.userinfo = res.userInfo;
        wx.setStorageSync(self.config.storage.wxUser, res.userInfo);
        if (isthrough) {
          self.getUserUkey(res.rawData, succ);
        }
      },
      fail:function(res){
        wx.openSetting({
          success:function(res){
            if(res.authSetting["scope.userInfo"]){
              wx.getUserInfo({
                success: res => {
                  // 可以將 res 發(fā)送給后臺解碼出 unionId
                  self.userinfo = res.userInfo;
                  wx.setStorageSync(self.config.storage.wxUser, res.userInfo);
                  if (isthrough) {
                    self.getUserUkey(res.rawData, succ);
                  }
                }
              });
            }
          }
        })
      }
    })
  },
  getUserUkey(rawData, succ){
    var self = this;
    var data = {
      code: wx.getStorageSync(self.config.storage.code),
      rawData: rawData
    };
    wx.request({
      url:self.config.requrl+"/Invest/api/wxLogin",
      data: data,
      method:"GET",
      success:function(res){
        res = res.data;
        if(res.code==1){
          wx.setStorageSync(self.config.storage.ukey,res.result.ukey);
          wx.setStorageSync(self.config.storage.ukeytime,new Date().getTime());
          self.getAuthenticationUserUkey(rawData, res.result.oid, succ);
        }
      }
    })
  },
  getAuthenticationUserUkey(rawData, openId, succ){
    var self = this;
    var data = {
      code: wx.getStorageSync(self.config.storage.code),
      rawData: JSON.parse(rawData),
      openId: openId,
      source: 2,
    };
    wx.request({
      url: self.config.couresurl + "/WechatApi/authentication",
      data: data,
      method: "POST",
      success: function (res) {
        res = res.data;
        if (res.resCode == 1) {
          wx.setStorageSync(self.config.storage.ukey_licaiyi, res.resObject);
          if (succ) {
            succ();
          }
        }
      }
    })
  },
  checkUkey(){
    var ukey = wx.getStorageSync(this.config.storage.ukey);
    var ukeyTime = wx.getStorageSync(this.config.storage.ukeytime);
    var tmpTime = new Date().getTime();
    var token = wx.getStorageSync(this.config.storage.ukey_licaiyi);
    if (tmpTime - ukeyTime >= 1000 * 60 * 60 * 12 || !token){
      ukey = "";
      this.login(null);
    } else {
      this.getWXUserInfo(false, null);
    }
  }
}

module.exports = user;

在掃碼的界面上我們首先校驗ukey,如果存在直接調(diào)用詳細的接口闰蛔,如果獲取不到ukey痕钢,說明微信尚未授權(quán),我們主動調(diào)用user模塊的login方法序六,在登錄的成功回調(diào)成功之后再執(zhí)行接口任连,便可解決該問題。
if (wx.getStorageSync(app.globalData.config.storage.ukey)) {
    this.starToConfig();
 } else {
    app.globalData.wxUser.login(function(){
       self.starToConfig();
    });
 }
該解決方案具有很大的局限性难咕,如果添加一個新的業(yè)務(wù)場景我們就需要多次判斷课梳,擴展性很差。但是對于只有這樣一個特殊場景來說余佃,還是適用的暮刃。

(3) 3.0版本微信授權(quán)

隨著業(yè)務(wù)的增加,微信小程序進行了更大的改版爆土,首頁不再強制需要授權(quán)椭懊。我的頁面則需要授權(quán)。在這樣的背景下,我們對授權(quán)機制和請求機制進行聯(lián)合氧猬,把授權(quán)的時機判斷放在后臺進行聯(lián)合判斷背犯。這樣就可以解決2.0遺漏下來的授權(quán)比較局限的問題。對于所有需要授權(quán)的地方后臺如果檢測到我們的接口用戶沒有授權(quán)盅抚,便返回統(tǒng)一的未授權(quán)的錯誤碼漠魏,小程序端對該狀態(tài)進行統(tǒng)一的操作,強制用戶登錄并在回調(diào)后執(zhí)行后續(xù)的接口妄均。
在request.js中柱锹, 我們對返回狀態(tài)進行了細分,分為請求成功丰包,請求錯誤禁熏,微信未授權(quán)等。
var app = getApp();

// 添加返回標識
var ResultCode = {
  ResultCodeSucc: 1,
  ResultCodeFail: -1,
  ResultCodeNoAccredit: -2
};

function ukeyData (data) {

  var okUkeyData = null;
  if (data) {
    var copyData = JSON.parse(JSON.stringify(data));
    var ukey = { "ukey": wx.getStorageSync(app.globalData.config.storage.ukey) };
    okUkeyData = Object.assign(copyData, ukey);
  } else {
    var ukey = { "ukey": wx.getStorageSync(app.globalData.config.storage.ukey) };
    okUkeyData = ukey;
  }
  return okUkeyData;
}

function post(data){
  req({
    url:data.url,
    method:"POST",
    data:ukeyData(data.data),
    succ:data.succ,
    error:data.error,
    no_accredit:data.no_accredit,
    fail:data.fail,
    complete:data.complete
  })
}

function get(data){
  req({
    url:data.url,
    method:"GET",
    data: ukeyData(data.data),
    succ:data.succ,
    error: data.error,
    no_accredit: data.no_accredit,
    fail:data.fail,
    complete:data.complete
  })
}

function req(data){
  wx.request({
    url: data.url,
    data: ukeyData(data.data),
    method: data.method, // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
    header: {
      'content-type':'application/x-www-form-urlencoded',
    }, // 設(shè)置請求的 header
    success: function(res){
      // success
      res = res.data;
     // 根據(jù)返回碼 分發(fā)行為
     if (res.code == ResultCode.ResultCodeSucc) {
        // 請求成功
        if (typeof data.succ === "function") {
          data.succ(res);
        }
      } else if (res.code == ResultCode.ResultCodeNoAccredit) {
        if (typeof data.no_accredit === "function") {
          // 微信未授權(quán)
          app.globalData.wxUser.login(function () {
            data.no_accredit(res);
          });
        }
      } else {
        // 請求錯誤
        if (typeof data.error === "function") {
          data.error(res);
        }
      }
    },
    fail:function(res){
      // 請求失敗
      if(typeof data.fail === "function"){
        data.fail(res);
      }
    },
    complete:function(res){
      if(typeof data.complete === "function"){
        data.complete(res);
      }
    }
  })
}

const request = {
  post:post,
  get:get
}

module.exports = request;

接口改造:
// 預(yù)約活動
  person_appointment_tap: function (e) {
    if (!this.data.isAppointment) {
      var self = this;
      request.post({
        url: app.globalData.config.requrl + "/Invest/Wx/subscribeMsg",
        data: {
          formid: e.detail.formId,
          activity_id: self.data.activity_id
        },
        header: {
          'content-type': 'application/x-www-form-urlencoded'
        },
        succ: function (res) {
          // 成功
          wx.showModal({
            title: '預(yù)約成功',
            content: "我們會在活動開始前給您發(fā)送消息提醒邑彪,請您及時關(guān)注",
            showCancel: false,
            confirmColor: "#ffcf00",
            success: function (res) {
            }
          })
          self.setData({ isAppointment: true });
        },
        error: function (res) {
          // 失敗
          prompt.showModal(res.code == 2 ? "您已經(jīng)預(yù)約過了瞧毙!" : "預(yù)約失敗,請稍后再試寄症!", null);
          if (res.code == 2) {
            self.setData({ isAppointment: true });
          }
        },
        no_accredit: function (res) {
          // 在授權(quán)成功后再次調(diào)用該接口即可
          self.person_appointment_tap(e);
        }
      })
    }
  }
  
我們在app.js中刪除用戶初始化代碼宙彪,在需要用戶第一次授權(quán)的地方就進行初始化即可。在3.0中瘸爽,我們將初始化授權(quán)代碼放在我的單頁的onLoad方法中您访,之后只要在后臺需要授權(quán)權(quán)限的地方,檢測到未授權(quán)剪决,就可提示到前端灵汪,讓前端進行用戶登錄授權(quán)了。

(4) 4.0版本微信授權(quán)(5月10日微信小程序授權(quán)調(diào)整)

5月10日微信小程序官方突然發(fā)布了新的微信小程序授權(quán)機制柑潦,用戶首次授權(quán)必須使用按鈕的方式進行顯示授權(quán)享言。對于這次更新我們也在原有的基礎(chǔ)上進行了改版,因為小程序的入口繁多而且微信沒有繼承的概念和像window一樣的頂級浮層渗鬼,就導(dǎo)致我們必須對授權(quán)機制進行統(tǒng)一管理览露。我們這次刪除了user.js,將授權(quán)及整個登陸機制放在封裝好的授權(quán)組件內(nèi)進行統(tǒng)一管理譬胎。并在接口處處理登陸失效的情況差牛,這樣就能很好的解決這次微信新授權(quán)機制對我們的影響。
微信小程序獲取用戶信息接口優(yōu)化調(diào)整文章 : 地址
(1)comp-auto組件
// index.js
var app = getApp();

Component({  
  properties: {
  },  
  data: {  
    show:false,
  },  
  methods: { 
    open(){
      this.setData({show:true});
    },
    close(){
      this.setData({show:false});
    },
      // 微信授權(quán)btn授權(quán)完成后會將用戶信息返回堰乔,我們在這個方法中可以直接獲取到用戶數(shù)據(jù)
    userauth(){
      var self = this;
      wx.getUserInfo({
        success:function(res){
          wx.setStorageSync(app.globalData.config.storage.wxUser, res.userInfo);
          self.getUserUkey(res.rawData,true);
        },
        fail:function(res){
          console.log("userinfo fail",res);
        }
      })
    },
    checkUkey() {
      var ukey = wx.getStorageSync(app.globalData.config.storage.ukey);
      var ukeyTime = wx.getStorageSync(app.globalData.config.storage.ukeytime);
      var tmpTime = new Date().getTime();
      if (tmpTime - ukeyTime >= 1000 * 60 * 60 * 12) {
        wx.setStorageSync(app.globalData.config.storage.ukey, "");
        this.login();
      } else {
        this.getWXUserInfo();
      }
    },
    login(){
      var self = this;
      wx.login({
        success:function(res){
          wx.setStorageSync(app.globalData.config.storage.code,res.code);
          self.getWXUserInfo();
        },
        fail:function(res){
          console.log("user login fail")
        }
      })
    },
    getWXUserInfo() {
      var self = this;
      wx.getUserInfo({
        success: function (res) {
          wx.setStorageSync(app.globalData.config.storage.wxUser, res.userInfo);
          self.getUserUkey(res.rawData, false);
        },
        fail: function (res) {
          // 防止已授權(quán)的用戶偏化,主動在設(shè)置中關(guān)閉授權(quán)后,可以彈出授權(quán)組件
          self.open();
        }
      })
    },
    getUserUkey(rawData, close) {
      var data = {
        code: wx.getStorageSync(app.globalData.config.storage.code),
        rawData: rawData
      }
      var self = this;
      wx.request({
        url: app.globalData.config.requrl + "",
        data: data,
        method: "GET",
        success: function (res) {
          res = res.data;
          if (res.code == 1) {
            wx.setStorageSync(app.globalData.config.storage.ukey, res.result.ukey);
            wx.setStorageSync(app.globalData.config.storage.ukeytime, new Date().getTime());
            if (close) {
              self.close();
            }
          }
        },
        fail: function (res) {
          console.log(res);
        },
        complete: function () {

          // 授權(quán)完成并獲取到用戶數(shù)據(jù)后镐侯,給頁面提供的回調(diào)
          self.triggerEvent("callback");
        }
      })
    },
    
    // 校驗是否授權(quán)
    judgeAuth: function () {

      var self = this;
      this.close();
      wx.getSetting({
        success(res) {
          if (res.authSetting['scope.userInfo']) {
            // 已經(jīng)授權(quán)關(guān)閉授權(quán)窗口
            // 直接調(diào)用已授權(quán)的方法
            self.close();
            self.triggerEvent("callback");
            return;
          } else {
            // 未授權(quán)去授權(quán)
            self.checkSession();
          }
        }
      })
    },

    checkSession: function () {

      var self = this;
      wx.checkSession({
        success: function (res) {
          //存在登錄狀態(tài)
          self.checkUkey();
        },
        fail: function () {
          //過期-重新登錄
          self.login();
        }
      });
    }
  },
})
// index.wxml 用戶可將授權(quán)button放在需要的地方
    <button class="auth_btn" type="default" open-type="getUserInfo" bindgetuserinfo="userauth">微信授權(quán)</button> 
(2)request.js
修改之前接口未獲取到用戶信息的處理侦讨,刪除自動登錄代碼將回調(diào)直接返回.request.js在3中給出了源碼,這邊就不再展示了。我們修改req方法韵卤。
function req(data){
  wx.request({
    url: data.url,
    data: ukeyData(data.data),
    method: data.method, // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
    header: {
      'content-type':'application/x-www-form-urlencoded',
    }, // 設(shè)置請求的 header
    success: function(res){
      // success
      res = res.data;
      if (res.code == ResultCode.ResultCodeSucc) {
        if (typeof data.succ === "function") {
          data.succ(res);
        }
      } else if (res.code == ResultCode.ResultCodeNoAccredit) {
        // 用戶登錄失效骗污,將回調(diào)直接放回
        if (typeof data.no_accredit === "function") {
          data.no_accredit(res);
        }
      } else {
        if (typeof data.error === "function") {
          data.error(res);
        }
      }
    },
    fail:function(res){
      if(typeof data.fail === "function"){
        data.fail(res);
      }
    },
    complete:function(res){
      if(typeof data.complete === "function"){
        data.complete(res);
      }
    }
  })
}
(3)在page中使用comp-auto組件
1.在onShow方法中校驗授權(quán)情況,未授權(quán)展示授權(quán)組件沈条,讓用戶授權(quán)
  /**
   * 生命周期函數(shù)--監(jiān)聽頁面顯示
   */
  onShow: function () {
    this.selectComponent("#compauth").judgeAuth();
  },
2.書寫授權(quán)組件回調(diào)需忿,在此方法中書寫只有授權(quán)才能調(diào)用的接口
  callback: function () {
    this.person_appointment_tap();
  }
3.修改需要授權(quán)才能使用的接口
 // 預(yù)約活動
  person_appointment_tap: function (e) {
    if (!this.data.isAppointment) {
      var self = this;
      request.post({
        url: app.globalData.config.requrl + "/Invest/Wx/subscribeMsg",
        data: {
          formid: e.detail.formId,
          activity_id: self.data.activity_id
        },
        succ: function (res) {
          // 成功
          wx.showModal({
            title: '預(yù)約成功',
            content: "我們會在活動開始前給您發(fā)送消息提醒,請您及時關(guān)注",
            showCancel: false,
            confirmColor: "#ffcf00",
            success: function (res) {
            }
          })
          self.setData({ isAppointment: true });
        },
        error: function (res) {
          // 失敗
          prompt.showModal(res.code == 2 ? "您已經(jīng)預(yù)約過了蜡歹!" : "預(yù)約失敗贴谎,請稍后再試!", null);
          if (res.code == 2) {
            self.setData({ isAppointment: true });
          }
        },
        no_accredit: function (res) {
          // 吊起授權(quán)組件登錄方法季稳,授權(quán)結(jié)束后會調(diào)用回調(diào)方法callback,再次請求該接口
        self.selectComponent("#compauth").login();
        }
      })
    }
  }
4.在index.json中添加組件
 {
  "usingComponents": {
   "compauth": "../../components/comp-auth/index"
  }
}
5.在index.wxml中添加組件
<compauth id="compauth" bind:callback="callback"></compauth>
這樣優(yōu)化后可以完善授權(quán)機制但是也有很大的弊端澈魄。因為微信沒有頂層視圖景鼠,所以導(dǎo)致了我們必須在每個需要授權(quán)的頁面添加組件。如果再修改授權(quán)機制痹扇,每個頁面都要進行維護铛漓,會產(chǎn)生很多的冗余代碼,讓項目變得難以維護鲫构。希望微信小程序之后可以考慮添加頂層視圖浓恶,減少碼農(nóng)的痛苦。

本文將持續(xù)對授權(quán)機制的處理進行更新结笨,謝謝大家的觀看包晰,有建議或者疑問歡迎給我留言。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末炕吸,一起剝皮案震驚了整個濱河市伐憾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌赫模,老刑警劉巖树肃,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異瀑罗,居然都是意外死亡胸嘴,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門斩祭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來劣像,“玉大人,你說我怎么就攤上這事停忿〖萁玻” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長吮铭。 經(jīng)常有香客問我时迫,道長,這世上最難降的妖魔是什么谓晌? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任掠拳,我火速辦了婚禮,結(jié)果婚禮上纸肉,老公的妹妹穿的比我還像新娘溺欧。我一直安慰自己,他們只是感情好柏肪,可當我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布姐刁。 她就那樣靜靜地躺著,像睡著了一般烦味。 火紅的嫁衣襯著肌膚如雪聂使。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天谬俄,我揣著相機與錄音柏靶,去河邊找鬼。 笑死溃论,一個胖子當著我的面吹牛屎蜓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播钥勋,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼炬转,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了笔诵?” 一聲冷哼從身側(cè)響起返吻,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎乎婿,沒想到半個月后测僵,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡谢翎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年捍靠,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片森逮。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡榨婆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出褒侧,到底是詐尸還是另有隱情良风,我是刑警寧澤谊迄,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站烟央,受9級特大地震影響统诺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜疑俭,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一粮呢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧钞艇,春花似錦啄寡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至飘弧,卻和暖如春姻乓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背眯牧。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留赖草,地道東北人学少。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像秧骑,于是被迫代替她去往敵國和親版确。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)載鏈接 注:本文轉(zhuǎn)載知乎上的回答 作者:初雪 鏈接:https://www.zhihu.com/question...
    pengshuangta閱讀 28,504評論 9 295
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,777評論 25 707
  • 過年回去幾天都是上午幫婆婆折菜乎折,下午找自己媽去了绒疗。打了三次牌,一次斗地主骂澄,兩次打麻將吓蘑。每年過年都是一家人嘮嗑嘮嗑,...
    蘇小文S閱讀 140評論 0 0
  • 記得有一句話這樣說“一個人得成功坟冲,20%是個人的知識儲備磨镶,80%來源于人脈”,以前對這句話沒有深入的思考健提,隨著...
    分秒早成閱讀 164評論 1 1
  • 夢見瓊瑤變成小姑娘琳猫,在和我討論她的劇本
    煙澀寒閱讀 82評論 0 0