文章目录
有状态服务
什么是状态
HTP协议中的状态
有状态服()
4-3 小程序的状态管理
小程序Stronge存储cookies
- 在utils中设置cookies.js
const key = 'cookie' function getSessionIDFromResponse(res){ var cookie = res.header['Set-Cookie'] console.log('get cookie from response: ', cookie) return cookie } function setCookieToStorage(cookie) { try { console.log(cookie) wx.setStorageSync(key, cookie) } catch (e) { console.log(e) } } function getCookieFromStorage() { var value = wx.getStorageSync(key) console.log(value) return value } module.exports = { setCookieToStorage: setCookieToStorage, getCookieFromStorage: getCookieFromStorage, getSessionIDFromResponse: getSessionIDFromResponse }
- 测试
Session中间件
4-4 实现登录功能
用户体系的建立
定义数据库模型
from django.db import models
# Create your models here.
class User(models.Model):
# open_id
open_id = models.CharField(max_length=64, unique=True)
# 昵称
nickname = models.CharField(max_length=256)
# 关注的城市
focus_cities = models.TextField(default='[]')
# 关注的星座
focus_constellations = models.TextField(default='[]')
# 关注的股票
focus_stocks = models.TextField(default='[]')
生成数据库模型
(venv) D:\Python_projects\backend-3-9>python manage.py makemigrations
Migrations for 'authorization':
authorization\migrations\0001_initial.py
- Create model User
(venv) D:\Python_projects\backend-3-9>python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, authorization, contenttypes, sessions
Running migrations:
No migrations to apply.
如果是测试号需要去申请去微信社区申请
前端从后端接口判断是否登录
// pages/homepage/homepage.js
const app = getApp()
const cookieUtil = require('../../utils/cookie.js')
Page({
/**
* 页面的初始数据
*/
data: {},
onReadCookies: function (){
wx.request({
url: app.globalData.serverUrl + app.globalData.apiVersion + '/auth/test',
success(res) {
var cookie = cookieUtil.getSessionIDFromResponse(res)
console.log(cookie)
}
}
)
},
// navigator跳转处理
onNavigatorTap: function (event) {
var that = this
var cookie = cookieUtil.getCookieFromStorage()
var header = {}
header.Cookie = cookie
wx.request({
url: app.globalData.serverUrl + '/api/v1.0/auth/status',
header: header,
success: function (res) {
var data = res.data.data
console.log(data)
if (data.is_authorized == 1) {
that.setData({
isLogin: true
})
app.setAuthStatus(true)
} else {
that.setData({
isLogin: false
})
app.setAuthStatus(false)
wx.showToast({
title: '请先授权登录',
})
}
if (data.is_authorized == 1){
// 获取由 data-type 标签传递过来的参数
console.log(event.currentTarget.dataset.type)
var navigatorType = event.currentTarget.dataset.type
if (navigatorType == 'focusCity') {
navigatorType = 'city'
} else if (navigatorType == 'focusStock') {
navigatorType = 'stock'
} else {
navigatorType = 'constellation'
}
var url = '../picker/picker?type=' + navigatorType
console.log('navigateTo url: ' + url)
wx.navigateTo({
url: '../picker/picker?type=' + navigatorType,
})
}
}
})
},
登录时获取并存储cookie
authorize: function () {
console.log('authorize')
var that = this
// 登陆并获取cookie
wx.login({
success: function (res) {
console.log(res)
var code = res.code
var appId = app.globalData.appId
var nickname = app.globalData.userInfo.nickName
// 请求后台
wx.request({
url: app.globalData.serverUrl + app.globalData.apiVersion + '/auth/authorize',
method: 'POST',
data: {
code: code,
appId: appId,
nickname: nickname
},
header: {
'content-type': 'application/json' // 默认值
},
success(res) {
wx.showToast({
title: '授权成功',
})
// 保存cookie
var cookie = cookieUtil.getSessionIDFromResponse(res)
cookieUtil.setCookieToStorage(cookie)
that.setData({
isLogin: true,
userInfo: app.globalData.userInfo,
hasUserInfo: true
})
app.setAuthStatus(true)
}
})
}
})
},
后端获取前端传递的个人信息openid
def __authorize_by_code(request):
'''
使用wx.login的到的临时code到微信提供的code2session接口授权
post_data = {
'encryptedData': 'xxxx',
'appId': 'xxx',
'sessionKey': 'xxx',
'iv': 'xxx'
}
'''
response = {}
post_data = request.body.decode('utf-8')
post_data = json.loads(post_data)
app_id = post_data.get('appId').strip()
nickname = post_data.get('nickname').strip()
code = post_data.get('code').strip()
print("code", code)
print("app_id", app_id)
if not (app_id and code):
response['result_code'] = ReturnCode.BROKEN_AUTHORIZED_DATA
response['message'] = 'authorized failed. need entire authorization data.'
return JsonResponse(response, safe=False)
try:
data = c2s(app_id, code)
except Exception as e:
print(e)
response['result_code'] = ReturnCode.FAILED
response['message'] = 'authorized failed.'
return JsonResponse(response, safe=False)
open_id = data.get('openid')
if not open_id:
response['result_code'] = ReturnCode.FAILED
response['message'] = 'authorization error.'
return JsonResponse(response, safe=False)
request.session['open_id'] = open_id
request.session['is_authorized'] = True
print("open_id", open_id)
# User.objects.get(open_id=open_id) # 不要用get,用get查询如果结果数量 !=1 就会抛异常
# 如果用户不存在,则新建用户
if not User.objects.filter(open_id=open_id):
new_user = User(open_id=open_id, nickname=nickname)
new_user.save()
message = 'user authorize successfully.'
response = wrap_json_response(data={}, code=ReturnCode.SUCCESS, message=message)
return JsonResponse(response, safe=False)
查看session_user
(venv) D:\Python_projects\backend-3-9>python manage.py dbshell
SQLite version 3.26.0 2018-12-01 12:34:55
Enter ".help" for usage hints.
sqlite> select * from authorization_user;
2|oXSML0ZH05BItFTFILfgCG6cTxik|咚咚呛!|[{"province": "\u5e7f\u4e1c\u7701", "area": "\u5357\u5c71\u533a", "city": "\u6df1\u5733\u5e02"}, {"province": "\u5e7f\u4e1c\u7701", "area": "\u76d0\u7530\u533a", "city": "\u6df1\u5733\u5e02"}]|["\u767d\u7f8a\u5ea7", "\u72ee\u5b50\u5ea7", "\u5904\u5973\u5ea7", "\u5c04\u624b\u5ea7"]|[{"name": "\u4e16\u7eaa\u661f\u6e90", "fullInfo": "\u6df1\u4ea4\u6240-\u4e16\u7eaa\u661f\u6e90(000005)", "market": "sz", "code": "000005"}, {"code": "000006", "name": "\u6df1\u632f\u4e1a\uff21", "fullInfo": "\u6df1\u4ea4\u6240-\u6df1\u632f\u4e1a\uff21(000006)", "market": "sz"}]
3|oRRtbv1RU2rC3zx2gTjoThOlLhas||[]|[]|[]
sqlite>
4-5 完善用户个人信息
查看个人信息
class UserView(View, CommonResponseMixin):
# 关注的城市、股票和星座
def get(self, request):
if not already_authorized(request):
response = self.wrap_json_response(code=ReturnCode.UNAUTHORIZED)
return JsonResponse(response, safe=False)
open_id = request.session.get('open_id')
user = User.objects.get(open_id=open_id)
data = {}
data['open_id'] = user.open_id
data['focus'] = {}
print(user.focus_cities)
data['focus']['city'] = json.loads(user.focus_cities)
data['focus']['constellation'] = json.loads(user.focus_constellations)
data['focus']['stock'] = json.loads(user.focus_stocks)
print('data: ', data)
response = CommonResponseMixin.wrap_json_response(code=ReturnCode.SUCCESS, data=data)
return JsonResponse(response, safe=False)
def post(self, request):
if not already_authorized(request):
response = self.wrap_json_response(code=ReturnCode.UNAUTHORIZED)
return JsonResponse(response, safe=False)
open_id = request.session.get('open_id')
user = User.objects.get(open_id=open_id)
# got str object
received_body = request.body.decode('utf-8')
received_body = eval(received_body)
cities = received_body.get('city')
stocks = received_body.get('stock')
constellations = received_body.get('constellation')
if cities == None: cities = []
if stocks == None: stocks = []
if constellations == None: constellations = []
user.focus_cities = json.dumps(cities)
user.focus_constellations = json.dumps(constellations)
user.focus_stocks = json.dumps(stocks)
user.save()
message = 'modify user info success.'
response = CommonResponseMixin.wrap_json_response(code=ReturnCode.SUCCESS, message=message)
return JsonResponse(response, safe=False)
4-6 复杂多变的用户状态管理
pages/picker.js
const cookieUtil = require('../../utils/cookie.js')
const szStock = require('../../resources/data/stock/sz-100.js')
const shStock = require('../../resources/data/stock/sh-100.js')
var allStockData = []
Array.prototype.push.apply(allStockData, szStock.data)
Array.prototype.push.apply(allStockData, shStock.data)
const app = getApp()
Page({
data: {
isConstellPicker: false,
isStockPicker: false,
isCityPicker: false,
personal: {
constellation: [],
city: [],
stock: []
},
allPickerData: {
allConstellation: ['白羊座', '金牛座', '双子座', '巨蟹座', '狮子座', '处女座', '天秤座', '天蝎座', '射手座', '摩羯座', '水瓶座', '双鱼座'],
allStock: []
}
},
onLoad: function(options) {
var that = this
// 1. 判断类型
console.log(options.type)
this.setData({
isConstellPicker: false,
isStockPicker: false,
isCityPicker: false,
})
if (options.type == 'city') {
this.setData({
isCityPicker: true,
})
} else if (options.type == 'constellation') {
this.setData({
isConstellPicker: true,
})
} else {
this.setData({
isStockPicker: true,
})
}
var newPickerData = this.data.allPickerData
newPickerData.allStock = allStockData
this.setData({
allPickerData: newPickerData
})
// 2. 加载数据
var header = {}
var cookie = cookieUtil.getCookieFromStorage()
header.Cookie = cookie
wx.request({
url: app.globalData.serverUrl + '/api/v1.0/auth/user',
method: 'GET',
header: header,
success(res) {
console.log(res)
that.setData({
personal: res.data.data.focus
})
}
})
},
bindConstellationPickerChange: function(e) {
console.log('constellPicker发送选择改变,携带值为', e.detail.value)
var newItem = this.data.allPickerData.allConstellation[e.detail.value]
var newData = this.data.personal.constellation
// 去重
if (newData.indexOf(newItem) > -1)
return
newData.push(newItem)
var newPersonalData = this.data.personal
newPersonalData.constellation = newData
this.setData({
personal: newPersonalData
})
},
bindStockPickerChange: function(e) {
var newItem = this.data.allPickerData.allStock[e.detail.value]
var newData = this.data.personal.stock
// 去重
for (var i = 0; i < newData.length; i++) {
if (newData[i].name == newItem.name && newData[i].code == newItem.code && newData[i].market == newItem.market) {
console.log('already exists.')
return
}
}
newData.push(newItem)
var newPersonalData = this.data.personal
newPersonalData.stock = newData
this.setData({
personal: newPersonalData
})
},
bindRegionPickerChange: function(e) {
console.log('cityPicker发送选择改变,携带值为', e.detail.value)
var pickerValue = e.detail.value
var newItem = {
province: pickerValue[0],
city: pickerValue[1],
area: pickerValue[2],
}
var newData = this.data.personal.city
// 去重
for (var i = 0; i < newData.length; i++) {
if (newData[i].province == newItem.province && newData[i].city == newItem.city && newData[i].area == newItem.area) {
console.log('already exists.')
return
}
}
newData.push(newItem)
var newPersonalData = this.data.personal
newPersonalData.city = newData
this.setData({
personal: newPersonalData
})
},
// 删除列表元素
deleteItem: function(e) {
var that = this
var deleteType = e.currentTarget.dataset.type
var index = e.currentTarget.dataset.index
console.log('delete type: ' + deleteType)
console.log('delete index: ' + index)
var personalData = this.data.personal
wx.showModal({
content: "确认删除此项吗?",
showCancel: true,
success: function(res) {
console.log(res)
if (res.confirm) {
if (deleteType == 'constellation') {
personalData.constellation.splice(index, 1)
} else if (deleteType == 'stock') {
personalData.stock.splice(index, 1)
} else {
personalData.city.splice(index, 1)
}
that.setData({
personal: personalData
})
that.onSave(false)
}
}
})
},
// 保存后台
onSave: function(isShowModal=true) {
var that = this
var header = {}
var cookie = cookieUtil.getCookieFromStorage()
header.Cookie = cookie
wx.request({
url: app.globalData.serverUrl + '/api/v1.0/auth/user',
method: 'POST',
data: {
city: that.data.personal.city,
stock: that.data.personal.stock,
constellation: that.data.personal.constellation
},
header: header,
success(res) {
console.log(res)
if (isShowModal){
wx.showToast({
title: '保存成功',
})
}
}
})
}
});
class UserView(View, CommonResponseMixin):
# 关注的城市、股票和星座
def get(self, request):
if not already_authorized(request):
response = self.wrap_json_response(code=ReturnCode.UNAUTHORIZED)
return JsonResponse(response, safe=False)
open_id = request.session.get('open_id')
user = User.objects.get(open_id=open_id)
data = {}
data['open_id'] = user.open_id
data['focus'] = {}
print(user.focus_cities)
data['focus']['city'] = json.loads(user.focus_cities)
data['focus']['constellation'] = json.loads(user.focus_constellations)
data['focus']['stock'] = json.loads(user.focus_stocks)
print('data: ', data)
response = CommonResponseMixin.wrap_json_response(code=ReturnCode.SUCCESS, data=data)
return JsonResponse(response, safe=False)
def post(self, request):
if not already_authorized(request):
response = self.wrap_json_response(code=ReturnCode.UNAUTHORIZED)
return JsonResponse(response, safe=False)
open_id = request.session.get('open_id')
user = User.objects.get(open_id=open_id)
# got str object
received_body = request.body.decode('utf-8')
received_body = eval(received_body)
cities = received_body.get('city')
stocks = received_body.get('stock')
constellations = received_body.get('constellation')
if cities == None: cities = []
if stocks == None: stocks = []
if constellations == None: constellations = []
user.focus_cities = json.dumps(cities)
user.focus_constellations = json.dumps(constellations)
user.focus_stocks = json.dumps(stocks)
user.save()
message = 'modify user info success.'
response = CommonResponseMixin.wrap_json_response(code=ReturnCode.SUCCESS, message=message)
return JsonResponse(response, safe=False)
4-7 有状态的首页(登录查询个人的添加记录)
首先判断是否登录,登录就从数据库中查询出数据,返回给前端展示,没有登陆提示未登录
# 星座运势
def constellation(request):
data = []
if already_authorized(request):
user = get_user(request)
print('星座:', user.focus_constellations)
constellations = json.loads(user.focus_constellations)
else:
constellations = all_constellations
for c in constellations:
result = thirdparty.juhe.constellation(c)
data.append(result)
response = CommonResponseMixin.wrap_json_response(data=data, code=ReturnCode.SUCCESS)
return JsonResponse(response, safe=False)
# 股票
def stock(request):
data = []
stocks = []
if already_authorized(request):
print("已登录")
user = get_user(request)
stocks = json.loads(user.focus_stocks)
else:
print("未登录")
stocks = popular_stocks
for stock in stocks:
result = thirdparty.juhe.stock(stock['market'], stock['code'])
data.append(result)
response = CommonResponseMixin.wrap_json_response(data=data, code=ReturnCode.SUCCESS)
return JsonResponse(response, safe=False)
# 笑话
def joke(request):
global joke_cache
if not joke_cache:
joke_cache = json.load(open(os.path.join(settings.BASE_DIR, 'jokes.json'), 'r'))
# 读缓存
all_jokes = joke_cache
limit = 10
sample_jokes = random.sample(all_jokes, limit)
response = CommonResponseMixin.wrap_json_response(data=sample_jokes, code=ReturnCode.SUCCESS)
return JsonResponse(response, safe=False)
首页index.js
//index.js
//获取应用实例
const app = getApp()
const cookieUtil = require('../../utils/cookie.js')
Page({
data: {
isAuthorized: false,
constellationData: null,
stockData: null,
weatherData: null
},
//事件处理函数
bindViewTap: function() {
wx.navigateTo({
url: '../logs/logs'
})
},
updateData: function() {
wx.showLoading({
title: '加载中',
})
var that = this
var cookie = cookieUtil.getCookieFromStorage()
var header = {}
header.Cookie = cookie
wx.request({
url: app.globalData.serverUrl + app.globalData.apiVersion + '/service/weather',
header: header,
success: function(res){
that.setData({
weatherData: res.data.data
})
wx.hideLoading()
}
})
wx.request({
url: app.globalData.serverUrl + app.globalData.apiVersion + '/service/constellation',
header: header,
success: function (res) {
that.setData({
constellationData: res.data.data
})
wx.hideLoading()
}
})
wx.request({
url: app.globalData.serverUrl + app.globalData.apiVersion + '/service/stock',
header: header,
success: function (res) {
that.setData({
stockData: res.data.data
})
wx.hideLoading()
}
})
},
onPullDownRefresh: function() {
var that = this
var cookie = cookieUtil.getCookieFromStorage()
var header = {}
header.Cookie = cookie
wx.request({
url: app.globalData.serverUrl + app.globalData.apiVersion + '/auth/status',
header: header,
success: function(res){
var data = res.data.data
if (data.is_authorized == 1){
that.setData({
isAuthorized: true
})
that.updateData()
}else{
that.setData({
isAuthorized: false
})
wx.showToast({
title: '请先授权登录',
})
}
}
})
},
onLoad: function() {
if (app.globalData.userInfo) {
this.setData({
userInfo: app.globalData.userInfo,
hasUserInfo: true
})
} else if (this.data.canIUse) {
// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
// 所以此处加入 callback 以防止这种情况
app.userInfoReadyCallback = res => {
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
} else {
// 在没有 open-type=getUserInfo 版本的兼容处理
wx.getUserInfo({
success: res => {
app.globalData.userInfo = res.userInfo
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
})
}
},
getUserInfo: function(e) {
console.log(e)
app.globalData.userInfo = e.detail.userInfo
this.setData({
userInfo: e.detail.userInfo,
hasUserInfo: true
})
}
})