Flask项目
Restful风格
REST:Representational State Transfer的缩写,翻译:“具象状态传输”。一般解释为“表现层状态转换”。
REST是设计风格而不是标准。是指客户端和服务器的交互形式。我们需要关注的重点是如何设计REST风格的网络接口。
REST的特点:
-
具象的。一般指表现层,要表现的对象就是资源。比如,客户端访问服务器,获取的数据就是资源。比如文字、图片、音视频等。
-
表现:资源的表现形式。txt格式、html格式、json格式、jpg格式等。浏览器通过URL确定资源的位置,但是需要在HTTP请求头中,用Accept和Content-Type字段指定,这两个字段是对资源表现的描述。
-
状态转换:客户端和服务器交互的过程。在这个过程中,一定会有数据和状态的转化,这种转化叫做状态转换。其中,GET表示获取资源,POST表示新建资源,PUT表示更新资源,DELETE表示删除资源。HTTP协议中最常用的就是这四种操作方式。
RESTful架构:
- 每个URL代表一种资源;
- 客户端和服务器之间,传递这种资源的某种表现层;
- 客户端通过四个http动词,对服务器资源进行操作,实现表现层状态转换。
如何设计符合RESTful风格的API
一、域名:
将api部署在专用域名下:
http://api.example.com
或者将api放在主域名下:
http://www.example.com/api/
二、版本:
将API的版本号放在url中。
http://www.example.com/app/1.0/info
http://www.example.com/app/1.2/info
三、路径:
路径表示API的具体网址。每个网址代表一种资源。 资源作为网址,网址中不能有动词只能有名词,一般名词要与数据库的表名对应。而且名词要使用复数。
错误示例:
http://www.example.com/getGoods
http://www.example.com/listOrders
正确示例:
#获取单个商品
http://www.example.com/app/goods/1
#获取所有商品
http://www.example.com/app/goods
四、使用标准的HTTP方法:
对于资源的具体操作类型,由HTTP动词表示。 常用的HTTP动词有四个。
GET SELECT :从服务器获取资源。
POST CREATE :在服务器新建资源。
PUT UPDATE :在服务器更新资源。
DELETE DELETE :从服务器删除资源。
示例:
#获取指定商品的信息
GET http://www.example.com/goods/ID
#新建商品的信息
POST http://www.example.com/goods
#更新指定商品的信息
PUT http://www.example.com/goods/ID
#删除指定商品的信息
DELETE http://www.example.com/goods/ID
五、过滤信息:
如果资源数据较多,服务器不能将所有数据一次全部返回给客户端。API应该提供参数,过滤返回结果。 实例:
#指定返回数据的数量
http://www.example.com/goods?limit=10
#指定返回数据的开始位置
http://www.example.com/goods?offset=10
#指定第几页,以及每页数据的数量
http://www.example.com/goods?page=2&per_page=20
六、状态码:
服务器向用户返回的状态码和提示信息,常用的有:
200 OK :服务器成功返回用户请求的数据
201 CREATED :用户新建或修改数据成功。
202 Accepted:表示请求已进入后台排队。
400 INVALID REQUEST :用户发出的请求有错误。
401 Unauthorized :用户没有权限。
403 Forbidden :访问被禁止。
404 NOT FOUND :请求针对的是不存在的记录。
406 Not Acceptable :用户请求的的格式不正确。
500 INTERNAL SERVER ERROR :服务器发生错误。
七、错误信息:
一般来说,服务器返回的错误信息,以键值对的形式返回。
{
error:'Invalid API KEY'
}
八、响应结果:
针对不同结果,服务器向客户端返回的结果应符合以下规范。
#返回商品列表
GET http://www.example.com/goods
#返回单个商品
GET http://www.example.com/goods/cup
#返回新生成的商品
POST http://www.example.com/goods
#返回一个空文档
DELETE http://www.example.com/goods
九、使用链接关联相关的资源:
在返回响应结果时提供链接其他API的方法,使客户端很方便的获取相关联的信息。
十、其他:
服务器返回的数据格式,应该尽量使用JSON,避免使用XML。
图片验证码
将生成验证码的包、response_code.py放入utils
api_1_0/verify_code.py
# coding:utf-8
from . import api
from ihome.utils.captcha.captcha import captcha
from ihome import redis_store, constants
from flask import current_app, jsonify, make_response
from ihome.utils.response_code import RET
# GET 127.0.0.1/api/v1.0/image_codes/<image_code_id>
@api.route("/image_codes/<image_code_id>")
def get_image_code(image_code_id):
"""
获取图片验证码
: params image_code_id: 图片验证码编号
:return: 正常:验证码图片 异常:返回json
"""
# 业务逻辑处理
# 生成验证码图片
# 名字,真实文本, 图片数据
name, text, image_data = captcha.generate_captcha()
# 将验证码真实值与编号保存到redis中, 设置有效期
# redis: 字符串 列表 哈希 set
# "key": xxx
# 使用哈希维护有效期的时候只能整体设置
# "image_codes": {"id1":"abc", "":"", "":""} 哈希 hset("image_codes", "id1", "abc") hget("image_codes", "id1")
# 单条维护记录,选用字符串
# "image_code_编号1": "真实值"
# "image_code_编号2": "真实值"
# redis_store.set("image_code_%s" % image_code_id, text)
# redis_store.expire("image_code_%s" % image_code_id, constants.IMAGE_CODE_REDIS_EXPIRES)
# 记录名字 有效期 记录值
try:
redis_store.setex("image_code_%s" % image_code_id, constants.IMAGE_CODE_REDIS_EXPIRES, text)
except Exception as e:
# 记录日志
current_app.logger.error(e)
# return jsonify(errno=RET.DBERR, errmsg="save image code id failed")
return jsonify(errno=RET.DBERR, errmsg="保存图片验证码失败")
# 返回图片
resp = make_response(image_data)
resp.headers["Content-Type"] = "image/jpg"
return resp
前端处理验证码
接口文档
- 分析需求
- 编写代码
- 编写单元测试
- 自测
- 编写接口文档
- 提测代码
接口文档
1. 接口名字
2. 描述(描述清楚接口的功能)
3. url
4. 请求方式
5. 传入参数
6. 返回值
接口:获取图片验证码
描述:前端访问,可以获取到验证码图片
url: /api/v1.0/image_codes/<image_code_id>
请求方式: GET
传入参数:
格式:路径参数 (参数是查询字符串、请求体的表单、json、xml)
名字 类型 是否必须 说明
image_code_id 字符串 是 验证码图片的编号
返回值:
格式: 正常:图片, 异常:json
名字 类型 是否必传 说明
errno 字符串 否 错误代码
errmsg 字符串 否 错误内容
实例:
'{"errno": "4001", "errmsg": "保存图片验证码失败"}'
发送短信服务
容联云 云通讯
www.yuntongxun.com
lib导入容联云SDK
封装
sms.py
# coding=utf-8
from CCPRestSDK import REST
# 主帐号
accountSid = '8aaf0708568d4143015697b0f4960888'
# 主帐号Token
accountToken = '42d3191f0e6745d6a9ddc6c795da0bed'
# 应用Id
appId = '8aaf0708568d4143015697b0f56e088f'
# 请求地址,格式如下,不需要写http://
serverIP = 'app.cloopen.com'
# 请求端口
serverPort = '8883'
# REST版本号
softVersion = '2013-12-26'
# 发送模板短信
# @param to 手机号码
# @param datas 内容数据 格式为列表 例如:['12','34'],如不需替换请填 ''
# @param $tempId 模板Id
class CCP(object):
"""自己封装的发送短信的辅助类"""
# 用来保存对象的类属性
instance = None
def __new__(cls):
# 判断CCP类有没有已经创建好的对象,如果没有,创建一个对象,并且保存
# 如果有,则将保存的对象直接返回
if cls.instance is None:
obj = super(CCP, cls).__new__(cls)
# 初始化REST SDK
obj.rest = REST(serverIP, serverPort, softVersion)
obj.rest.setAccount(accountSid, accountToken)
obj.rest.setAppId(appId)
cls.instance = obj
return cls.instance
def send_template_sms(self, to, datas, temp_id):
""""""
result = self.rest.sendTemplateSMS(to, datas, temp_id)
# for k, v in result.iteritems():
#
# if k == 'templateSMS':
# for k, s in v.iteritems():
# print '%s:%s' % (k, s)
# else:
# print '%s:%s' % (k, v)
# smsMessageSid:ff75e0f84f05445ba08efdd0787ad7d0
# dateCreated:20171125124726
# statusCode:000000
status_code = result.get("statusCode")
if status_code == "000000":
# 表示发送短信成功
return 0
else:
# 发送失败
return -1
if __name__ == '__main__':
ccp = CCP()
ret = ccp.send_template_sms("18516952650", ["1234", "5"], 1)
print(ret)
verify_code.py
from . import api
from ihome.utils.captcha.captcha import captcha
from ihome import redis_store, constants, db
from flask import current_app, jsonify, make_response, request
from ihome.utils.response_code import RET
from ihome.models import User
from ihome.libs.yuntongxun.sms import CCP
import random
# GET /api/v1.0/sms_codes/<mobile>?image_code=xxxx&image_code_id=xxxx
@api.route("/sms_codes/<re(r'1[34578]\d{9}'):mobile>")
def get_sms_code(mobile):
"""获取短信验证码"""
# 获取参数
image_code = request.args.get("image_code")
image_code_id = request.args.get("image_code_id")
# 校验参数
if not all([image_code_id, image_code]):
# 表示参数不完整
return jsonify(errno=RET.PARAMERR, errmsg="参数不完整")
# 业务逻辑处理
# 从redis中取出真实的图片验证码
try:
real_image_code = redis_store.get("image_code_%s" % image_code_id)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="redis数据库异常")
# 判断图片验证码是否过期
if real_image_code is None:
# 表示图片验证码没有或者过期
return jsonify(errno=RET.NODATA, errmsg="图片验证码失效")
# 删除redis中的图片验证码,防止用户使用同一个图片验证码验证多次
try:
redis_store.delete("image_code_%s" % image_code_id)
except Exception as e:
current_app.logger.error(e)
# 与用户填写的值进行对比
if real_image_code.lower() != image_code.lower():
# 表示用户填写错误
return jsonify(errno=RET.DATAERR, errmsg="图片验证码错误")
# 判断对于这个手机号的操作,在60秒内有没有之前的记录,如果有,则认为用户操作频繁,不接受处理
try:
send_flag = redis_store.get("send_sms_code_%s" % mobile)
except Exception as e:
current_app.logger.error(e)
else:
if send_flag is not None:
# 表示在60秒内之前有过发送的记录
return jsonify(errno=RET.REQERR, errmsg="请求过于频繁,请60秒后重试")
# 判断手机号是否存在
try:
user = User.query.filter_by(mobile=mobile).first()
except Exception as e:
current_app.logger.error(e)
else:
if user is not None:
# 表示手机号已存在
return jsonify(errno=RET.DATAEXIST, errmsg="手机号已存在")
# 如果手机号不存在,则生成短信验证码
sms_code = "%06d" % random.randint(0, 999999)
# 保存真实的短信验证码
try:
redis_store.setex("sms_code_%s" % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
# 保存发送给这个手机号的记录,防止用户在60s内再次出发发送短信的操作
redis_store.setex("send_sms_code_%s" % mobile, constants.SEND_SMS_CODE_INTERVAL, 1)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="保存短信验证码异常")
# 发送短信
try:
ccp = CCP()
result = ccp.send_template_sms(mobile, [sms_code, int(constants.SMS_CODE_REDIS_EXPIRES/60)], 1)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.THIRDERR, errmsg="发送异常")
# 返回值
if result == 0:
# 发送成功
return jsonify(errno=RET.OK, errmsg="发送成功")
else:
return jsonify(errno=RET.THIRDERR, errmsg="发送失败")
测试
前端发送短信验证码
function sendSMSCode() {
// 点击发送短信验证码后被执行的函数
$(".phonecode-a").removeAttr("onclick");
var mobile = $("#mobile").val();
if (!mobile) {
$("#mobile-err span").html("请填写正确的手机号!");
$("#mobile-err").show();
$(".phonecode-a").attr("onclick", "sendSMSCode();");
return;
}
var imageCode = $("#imagecode").val();
if (!imageCode) {
$("#image-code-err span").html("请填写验证码!");
$("#image-code-err").show();
$(".phonecode-a").attr("onclick", "sendSMSCode();");
return;
}
// 构造向后端请求的参数
var req_data = {
image_code: imageCode, // 图片验证码的值
image_code_id: imageCodeId // 图片验证码的编号,(全局变量)
};
// 向后端发送请求
$.get("/api/v1.0/sms_codes/"+ mobile, req_data, function (resp) {
// resp是后端返回的响应值,因为后端返回的是json字符串,
// 所以ajax帮助我们把这个json字符串转换为js对象,resp就是转换后对象
if (resp.errno == "0") {
var num = 60;
// 表示发送成功
var timer = setInterval(function () {
if (num >= 1) {
// 修改倒计时文本
$(".phonecode-a").html(num + "秒");
num -= 1;
} else {
$(".phonecode-a").html("获取验证码");
$(".phonecode-a").attr("onclick", "sendSMSCode();");
clearInterval(timer);
}
}, 1000, 60)
} else {
alert(resp.errmsg);
$(".phonecode-a").attr("onclick", "sendSMSCode();");
}
});
}
注册、登录、登出逻辑
所有常量参数保存在constants.py
# coding:utf-8
# 图片验证码的redis有效期, 单位:秒
IMAGE_CODE_REDIS_EXPIRES = 180
# 短信验证码的redis有效期, 单位:秒
SMS_CODE_REDIS_EXPIRES = 300
# 发送短信验证码的间隔, 单位:秒
SEND_SMS_CODE_INTERVAL = 60
# 登录错误尝试次数
LOGIN_ERROR_MAX_TIMES = 5
# 登录错误限制的时间, 单位:秒
LOGIN_ERROR_FORBID_TIME = 600
# 七牛的域名
QINIU_URL_DOMAIN = "http://o91qujnqh.bkt.clouddn.com/"
# 城区信息的缓存时间, 单位:秒
AREA_INFO_REDIS_CACHE_EXPIRES = 7200
passport.py
# coding:utf-8
from . import api
from flask import request, jsonify, current_app, session
from ihome.utils.response_code import RET
from ihome import redis_store, db, constants
from ihome.models import User
from sqlalchemy.exc import IntegrityError
import re
@api.route("/users", methods=["POST"])
def register():
"""注册
请求的参数: 手机号、短信验证码、密码、确认密码
参数格式:json
"""
# 获取请求的json数据,返回字典
req_dict = request.get_json()
mobile = req_dict.get("mobile")
sms_code = req_dict.get("sms_code")
password = req_dict.get("password")
password2 = req_dict.get("password2")
# 校验参数
if not all([mobile, sms_code, password, password2]):
return jsonify(errno=RET.PARAMERR, errmsg="参数不完整")
# 判断手机号格式
if not re.match(r"1[34578]\d{9}", mobile):
# 表示格式不对
return jsonify(errno=RET.PARAMERR, errmsg="手机号格式错误")
if password != password2:
return jsonify(errno=RET.PARAMERR, errmsg="两次密码不一致")
# 从redis中取出短信验证码
try:
real_sms_code = redis_store.get("sms_code_%s" % mobile)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="读取真实短信验证码异常")
# 判断短信验证码是否过期
if real_sms_code is None:
return jsonify(errno=RET.NODATA, errmsg="短信验证码失效")
# 删除redis中的短信验证码,防止重复使用校验
try:
redis_store.delete("sms_code_%s" % mobile)
except Exception as e:
current_app.logger.error(e)
# 判断用户填写短信验证码的正确性
if real_sms_code != sms_code:
return jsonify(errno=RET.DATAERR, errmsg="短信验证码错误")
# 判断用户的手机号是否注册过
# try:
# user = User.query.filter_by(mobile=mobile).first()
# except Exception as e:
# current_app.logger.error(e)
# return jsonify(errno=RET.DBERR, errmsg="数据库异常")
# else:
# if user is not None:
# # 表示手机号已存在
# return jsonify(errno=RET.DATAEXIST, errmsg="手机号已存在")
# 盐值 salt
# 注册
# 用户1 password="123456" + "abc" sha1 abc$hxosifodfdoshfosdhfso
# 用户2 password="123456" + "def" sha1 def$dfhsoicoshdoshfosidfs
#
# 用户登录 password ="123456" "abc" sha256 sha1 hxosufodsofdihsofho
# 保存用户的注册数据到数据库中
user = User(name=mobile, mobile=mobile)
# user.generate_password_hash(password)
user.password = password # 设置属性
try:
db.session.add(user)
db.session.commit()
except IntegrityError as e:
# 数据库操作错误后的回滚
db.session.rollback()
# 表示手机号出现了重复值,即手机号已注册过
current_app.logger.error(e)
return jsonify(errno=RET.DATAEXIST, errmsg="手机号已存在")
except Exception as e:
db.session.rollback()
# 表示手机号出现了重复值,即手机号已注册过
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="查询数据库异常")
# 保存登录状态到session中
session["name"] = mobile
session["mobile"] = mobile
session["user_id"] = user.id
# 返回结果
return jsonify(errno=RET.OK, errmsg="注册成功")
@api.route("/sessions", methods=["POST"])
def login():
"""用户登录
参数: 手机号、密码, json
"""
# 获取参数
req_dict = request.get_json()
mobile = req_dict.get("mobile")
password = req_dict.get("password")
# 校验参数
# 参数完整的校验
if not all([mobile, password]):
return jsonify(errno=RET.PARAMERR, errmsg="参数不完整")
# 手机号的格式
if not re.match(r"1[34578]\d{9}", mobile):
return jsonify(errno=RET.PARAMERR, errmsg="手机号格式错误")
# 判断错误次数是否超过限制,如果超过限制,则返回
# redis记录: "access_nums_请求的ip": "次数"
user_ip = request.remote_addr # 用户的ip地址
try:
access_nums = redis_store.get("access_num_%s" % user_ip)
except Exception as e:
current_app.logger.error(e)
else:
if access_nums is not None and int(access_nums) >= constants.LOGIN_ERROR_MAX_TIMES:
return jsonify(errno=RET.REQERR, errmsg="错误次数过多,请稍后重试")
# 从数据库中根据手机号查询用户的数据对象
try:
user = User.query.filter_by(mobile=mobile).first()
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="获取用户信息失败")
# 用数据库的密码与用户填写的密码进行对比验证
if user is None or not user.check_password(password):
# 如果验证失败,记录错误次数,返回信息
try:
# redis的incr可以对字符串类型的数字数据进行加一操作,如果数据一开始不存在,则会初始化为1
redis_store.incr("access_num_%s" % user_ip)
redis_store.expire("access_num_%s" % user_ip, constants.LOGIN_ERROR_FORBID_TIME)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DATAERR, errmsg="用户名或密码错误")
# 如果验证相同成功,保存登录状态, 在session中
session["name"] = user.name
session["mobile"] = user.mobile
session["user_id"] = user.id
return jsonify(errno=RET.OK, errmsg="登录成功")
@api.route("/session", methods=["GET"])
def check_login():
"""检查登陆状态"""
# 尝试从session中获取用户的名字
name = session.get("name")
# 如果session中数据name名字存在,则表示用户已登录,否则未登录
if name is not None:
return jsonify(errno=RET.OK, errmsg="true", data={
"name": name})
else:
return jsonify(errno=RET.SESSIONERR, errmsg="false")
@api.route("/session", methods=["DELETE"])
def logout():
"""登出"""
# 清除session数据
session.clear()
return jsonify(errno=RET.OK, errmsg="OK")
model.py 处理用户密码加密部分
from datetime import datetime
from . import db
from werkzeug.security import generate_password_hash, check_password_hash
class User(BaseModel, db.Model):
"""用户"""
__tablename__ = "ih_user_profile"
id = db.Column(db.Integer, primary_key=True) # 用户编号
name = db.Column(db.String(32), unique=True, nullable=False) # 用户暱称
password_hash = db.Column(db.String(128), nullable=False) # 加密的密码
mobile = db.Column(db.String(11), unique=True, nullable=False) # 手机号
real_name = db.Column(db.String(32)) # 真实姓名
id_card = db.Column(db.String(20)) # 身份证号
avatar_url = db.Column(db.String(128)) # 用户头像路径
houses = db.relationship("House", backref="user") # 用户发布的房屋
orders = db.relationship("Order", backref="user") # 用户下的订单
# 加上property装饰器后,会把函数变为属性,属性名即为函数名
@property
def password(self):
"""读取属性的函数行为"""
# print(user.password) # 读取属性时被调用
# 函数的返回值会作为属性值
# return "xxxx"
raise AttributeError("这个属性只能设置,不能读取")
# 使用这个装饰器, 对应设置属性操作
@password.setter
def password(self, value):
"""
设置属性 user.passord = "xxxxx"
:param value: 设置属性时的数据 value就是"xxxxx", 原始的明文密码
:return:
"""
self.password_hash = generate_password_hash(value)
# def generate_password_hash(self, origin_password):
# """对密码进行加密"""
# self.password_hash = generate_password_hash(origin_password)
def check_password(self, passwd):
"""
检验密码的正确性
:param passwd: 用户登录时填写的原始密码
:return: 如果正确,返回True, 否则返回False
"""
return check_password_hash(self.password_hash, passwd)
前端部分
register.js
// js读取cookie的方法
function getCookie(name) {
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] : undefined;
}
// 为表单的提交补充自定义的函数行为 (提交事件e)
$(".form-register").submit(function(e){
// 阻止浏览器对于表单的默认自动提交行为
e.preventDefault();
var mobile = $("#mobile").val();
var phoneCode = $("#phonecode").val();
var passwd = $("#password").val();
var passwd2 = $("#password2").val();
if (!mobile) {
$("#mobile-err span").html("请填写正确的手机号!");
$("#mobile-err").show();
return;
}
if (!phoneCode) {
$("#phone-code-err span").html("请填写短信验证码!");
$("#phone-code-err").show();
return;
}
if (!passwd) {
$("#password-err span").html("请填写密码!");
$("#password-err").show();
return;
}
if (passwd != passwd2) {
$("#password2-err span").html("两次密码不一致!");
$("#password2-err").show();
return;
}
// 调用ajax向后端发送注册请求
var req_data = {
mobile: mobile,
sms_code: phoneCode,
password: passwd,
password2: passwd2,
};
var req_json = JSON.stringify(req_data);
$.ajax({
url: "/api/v1.0/users",
type: "post",
data: req_json,
contentType: "application/json",
dataType: "json",
headers: {
"X-CSRFToken": getCookie("csrf_token")
}, // 请求头,将csrf_token值放到请求中,方便后端csrf进行验证
success: function (resp) {
if (resp.errno == "0") {
// 注册成功,跳转到主页
location.href = "/index.html";
} else {
alert(resp.errmsg);
}
}
})
});
})
login.js
function getCookie(name) {
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] : undefined;
}
$(document).ready(function() {
$("#mobile").focus(function(){
$("#mobile-err").hide();
});
$("#password").focus(function(){
$("#password-err").hide();
});
$(".form-login").submit(function(e){
e.preventDefault();
mobile = $("#mobile").val();
passwd = $("#password").val();
if (!mobile) {
$("#mobile-err span").html("请填写正确的手机号!");
$("#mobile-err").show();
return;
}
if (!passwd) {
$("#password-err span").html("请填写密码!");
$("#password-err").show();
return;
}
// 将表单的数据存放到对象data中
var data = {
mobile: mobile,
password: passwd
};
// 将data转为json字符串
var jsonData = JSON.stringify(data);
$.ajax({
url:"/api/v1.0/sessions",
type:"post",
data: jsonData,
contentType: "application/json",
dataType: "json",
headers:{
"X-CSRFToken":getCookie("csrf_token")
},
success: function (data) {
if (data.errno == "0") {
// 登录成功,跳转到主页
location.href = "/";
}
else {
// 其他错误信息,在页面中展示
$("#password-err span").html(data.errmsg);
$("#password-err").show();
}
}
});
});
})
检查登录
index.js
$(document).ready(function(){
// 检查用户的登录状态
$.get("/api/v1.0/session", function(resp) {
if ("0" == resp.errno) {
$(".top-bar>.user-info>.user-name").html(resp.data.name);
$(".top-bar>.user-info").show();
} else {
$(".top-bar>.register-login").show();
}
}, "json");
登出
function getCookie(name) {
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] : undefined;
}
// 点击推出按钮时执行的函数
function logout() {
$.ajax({
url: "/api/v1.0/session",
type: "delete",
headers: {
"X-CSRFToken": getCookie("csrf_token")
},
dataType: "json",
success: function (resp) {
if ("0" == resp.errno) {
location.href = "/index.html";
}
}
});
}
$(document).ready(function(){
})