restful API demo

博客回顾了JsonResponse类,它可将对象转为json字符串并封装成Response对象返回。默认只能对字典dump,非字典数据需传safe=False。还介绍了用户管理系统视图设计回传参数,对JsonResponse进行封装,约定状态码,添加kwargs参数,进一步封装返回值为函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JsonResponse类回顾:

  1. 作为HttpResponseBase中重要的子类,content_type类型为application/json(json传输)
  2. 用来对象dump成json字符串,然后返回将json字符串封装成Response对象返回给浏览器。
  3. 代码demo:
from django.http import JsonResponse
def index(request):
    return JsonResponse({"telephone":"123456789","age":18})
  1. 默认情况下JsonResponse只能对字典进行dump,如果想要对非字典的数据进行dump,那么需要给JsonResponse传递一个safe=False参数。代码demo:
from django.http import JsonResponse
def index(request):
    persons = ['张三','李四','王五']
    return HttpResponse(persons)

以上代码会报错,应该在使用HttpResponse的时候,传入一个safe=False参数,返回值应为

return HttpResponse(persons,safe=False)

一个用户管理系统视图设计回传参数

  1. 封装JsonResponse
  2. 和前端约定状态码200正确400参数错误401户授权信息错误405方法请求错误500服务器错误
    此处默认返回消息为空,数据为空,状态码为正确(从测试的角度来讲,初始化状态码为正确可能会导致异常情况的遗漏判定,待定)
  3. 初设codemessagedata,考虑到可能会传入token值,遂添加kwargs参数(需为dict类型)
  4. 考虑到多种code返回值,进一步封装code值为函数,便于函数书写和代码审阅,messagedata值随机应变
#encoding: utf-8
from django.http import JsonResponse

class HttpCode(object):
    ok = 200
    paramserror = 400
    unauth = 401
    methoderror = 405
    servererror = 500

# {"code":400,"message":"","data":{}}
def result(code=HttpCode.ok,message="",data=None,kwargs=None):
    json_dict = {"code":code,"message":message,"data":data}

    if kwargs and isinstance(kwargs,dict) and kwargs.keys():
        json_dict.update(kwargs)

    return JsonResponse(json_dict)


def ok():
    return result()


def params_error(message="",data=None):
    return result(code=HttpCode.paramserror,message=message,data=data)

def unauth(message="",data=None):
    return result(code=HttpCode.unauth,message=message,data=data)

def method_error(message='',data=None):
    return result(code=HttpCode.methoderror,message=message,data=data)

def server_error(message='',data=None):
    return result(code=HttpCode.servererror,message=message,data=data)

封装后的视图

#encoding: utf-8

from django.contrib.auth import login,logout,authenticate
from django.views.decorators.http import require_POST
from .forms import LoginForm,RegisterForm
from utils import restful
from django.shortcuts import redirect,reverse
from utils.captcha.xfzcaptcha import Captcha
from io import BytesIO
from django.http import HttpResponse
from django.core.cache import cache
from django.contrib.auth import get_user_model
from utils import smssender

User = get_user_model()

@require_POST
def login_view(request):
    form = LoginForm(request.POST)
    if form.is_valid():
        telephone = form.cleaned_data.get('telephone')
        password = form.cleaned_data.get('password')
        remember = form.cleaned_data.get('remember')
        user = authenticate(request,username=telephone,password=password)
        if user:
            if user.is_active:
                login(request,user)
                if remember:
                    request.session.set_expiry(None)
                else:
                    request.session.set_expiry(0)
                return restful.ok()
            else:
                return restful.unauth(message="您的账号已经被冻结了!")
        else:
            return restful.params_error(message="手机号或者密码错误!")
    else:
        errors = form.get_errors()
        # {"password":['密码最大长度不能超过20为!','xxx'],"telephone":['xx','x']}
        return restful.params_error(message=errors)


def logout_view(request):
    logout(request)
    return redirect(reverse('index'))


@require_POST
def register(request):
    form = RegisterForm(request.POST)
    if form.is_valid():
        telephone = form.cleaned_data.get('telephone')
        username = form.cleaned_data.get('username')
        password = form.cleaned_data.get('password1')
        user = User.objects.create_user(telephone=telephone,username=username,password=password)
        login(request,user)
        return restful.ok()
    else:
        return restful.params_error(message=form.get_errors())


def img_captcha(request):
    text,image = Captcha.gene_code()
    # BytesIO:相当于一个管道,用来存储图片的流数据
    out = BytesIO()
    # 调用image的save方法,将这个image对象保存到BytesIO中
    image.save(out,'png')
    # 将BytesIO的文件指针移动到最开始的位置
    out.seek(0)

    response = HttpResponse(content_type='image/png')
    # 从BytesIO的管道中,读取出图片数据,保存到response对象上
    response.write(out.read())
    response['Content-length'] = out.tell()

    # 12Df:12Df.lower()
    cache.set(text.lower(),text.lower(),5*60)

    return response


def sms_captcha(request):
    # /sms_captcha/?telephone=xxx
    telephone = request.GET.get('telephone')
    code = Captcha.gene_text()
    cache.set(telephone,code,5*60)
    #短信验证码测试,验证码打印在控制台,后期删除
    print('短信验证码:',code)
    # result = aliyunsms.send_sms(telephone,code)
    result = smssender.send(telephone,code)
    if result:
        return restful.ok()
    else:
        return result.params_error(message="短信验证码发送失败!")


def cache_test(request):
    cache.set('username','zhiliao',60)
    result = cache.get('username')
    return HttpResponse('success')
(1)项目简介 这个demo很简单,是一个记账小工程。用户可以注册、修改密码,可以记账、查找记账记录等。 (2)接口介绍 用户操作相关: post /users 用户注册 post /users/login 用户登录(这里我把login当成一个名词) put /users/pwd?userId=xxx&sign=xxx 用户修改密码 delete /users?uerId=xxx&sign=xxx 删除用户 记账记录操作相关: post /records?userId=xxx&sign=xxx 增加一条记账记录 get /records/:id?userId=xxx&sign=xxx 查询一条记账记录详情 put /records/:id?userId=xxx&sign=xxx 修改一条记账记录详情 get /records?查询参数&userId=xxx&sign=xxx 分页查询记账记录 delete /records/:id?userId=xxx&sign=xxx 删除一条记账记录 其中url中带sign参数的表示该接口需要鉴权,sign必须是url中最后一个参数。具体的鉴权方法是:用户登录后,服务器生成返回一个token,然后客户端要注意保存这个token,需要鉴权的接口加上sign签名,sign=MD5(url+token),这样可以避免直接传token从而泄露了token。这里我觉得接口最好还带一个时间戳参数timestamp,然后可以在服务端比较时间差,从而避免重放攻击。而且这样还有一个好处,就是如果有人截获了我们的请求,他想伪造我们的请求则不得不改时间戳参数(因为我们在服务器端会比较时间),这样一来sign势必会改变,他是无法得知这个sign的。如果我们没有加时间戳参数的话,那么,他截获了请求url,再重发这个请求势必又是一次合法的请求。我在这里为了简单一些,就不加时间戳了,因为这在开发测试阶段实在是太麻烦了。 (3)关于redis和数据库的说明 服务端在用户登录后,生成token,并将token保存到redis中。后面在接口鉴权的时候会取出token计算签名MD5(除sign外的url+token),进行比对。 这个demo搭建了一个redis主从复制,具体可以参考:http://download.youkuaiyun.com/detail/zhutulang/9585010 数据库使用mysql,脚本在 src/main/resources/accounting.sql
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值