一、前言

1、版本的重要性

RESTful 规范中,有关版本的问题,用restful规范做开放接口的时候,用户请求API,系统返回数据。但是难免在系统发展的过程中,不可避免的需要添加新的资源,或者修改现有资源。因此,改动升级必不可少,但是,作为平台开发者,应该知道:一旦你的API开放出去,有人开始用了,平台的任何改动都需要考虑对当前用户的影响。因此,做开放平台,从第一个API的设计就需要开始API的版本控制策略问题,API的版本控制策略就像是开放平台和平台用户之间的长期协议,其设计的好坏将直接决定用户是否使用该平台,或者说用户在使用之后是否会因为某次版本升级直接弃用该平台。

2、定义版本

怎么定义版本协议,前端后端怎么协调。有以下几种方式:

  • 请求头中定义
    GET /something/ HTTP/1.1
Host: example.com
Accept: application/json; version=1.0 #版本为1.0
  • URL中定义
    URL: example.com/v1.0/  # 版本为1.0
GET /1.0/something/ HTTP/1.1
Host: example.com
Accept: application/json
  • 子域名中定义
    GET /something/ HTTP/1.1
Host: v1.example.com # 版本为1.0
Accept: application/json
  • HttpReqeust参数传递
    GET /something/?version=0.1 HTTP/1.1  # 版本为1.0
Host: example.com
Accept: application/json

二、示例

django rest framewrok中,如果没有在配置文件setting.py中设置默认的VERSION_PARAM,即版本参数,drf会设置默认的参数为version,并将获取到的version的值封装到request.version

1、请求头中定义

django rest frameworkrequest其实是对原生的DjangoHttpRequest做了一个封装,通过直接获取属性可以获取到请求头中的版本号

django rest framework的request

原生的DjangoHttpRequest

请求头的版本和其他请求头信息最终会放到META中,因此想要获取版本号可以如下这样

version = request._request.META.get('version')  # 获取版本号

2、子域名中定义

同样的像请求头中定义一样,在请求头中也可以直接获取的域名,放到META中,因此想要获取版本号可以如下这样

host = request._request.META.get('HTTP_HOST')  # 先获取主机域名
version = host.split('.')[0] # 获取版本号

注:其实在django rest framework内部也有关于以上两种定义版本的处理方法

3、HttpReqeust参数传递

之前分别在django rest framework中关于节流,认证,权限三个组件,这里新建一个Django项目,命名为drf2。并进入当前目录下执行python manage.py startapp api,将新建的app,和rest_framework放入INSTALLED_APPS。

# setting.py

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'api'
]

<1>、目录结构

<2>、路由系统

from django.conf.urls import url

from .views import VersionView

urlpatterns = [
url(r'^version/$', VersionView.as_view()), ]

<3>、视图

from django.http import JsonResponse
from rest_framework.views import APIView
from rest_framework.versioning import QueryParameterVersioning class VersionView(APIView):
versioning_class = QueryParameterVersioning # 局部配置请求参数处理 def get(self, request, *args, **kwargs):
version = request.version
ret = {
'code': 1000,
'msg': '请求成功',
‘version': version
}
return JsonResponse(ret)

<4>、配置文件

像之前在权限,节流那样,可以配置一个全局默认的版本解析类

REST_FRAMEWORK = {
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning", # 默认是url处理版本
"DEFAULT_VERSION":'v1', # 默认版本
"ALLOWED_VERSIONS":['v1','v2'], # 允许版本
"VERSION_PARAM":'version', # 版本参数例如 ?version=v1,,则表示版本为v1
}

<5>、测试

使用postman或者浏览器发送请求测试

提供正常版本号http://127.0.0.1:8000/api/version/?version=v1 获取版本成功

发送错误版本号http://127.0.0.1:8000/api/version/?version=v3 由于允许版本只有v1和v2,所以版本错误,返回错误信息

不提供版本号:假如在url请求中不添加参数,http://127.0.0.1:8000/api/version/?,能获取到默认的版本号

4、URL中定义

在url中定义,例如http://127.0.0.1:8000/api/v1/

<1>、路由系统

from django.conf.urls import url

from .views import VersionView

urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/$', VersionView.as_view()), # 可用版本为v1和v2
]

<2>、视图

from django.http import JsonResponse
from django.http import HttpRequest
from rest_framework.views import APIView, Request
from rest_framework.versioning import URLPathVersioning class VersionView(APIView):
versioning_class = URLPathVersioning # 局部配置版本类 def get(self, request, *args, **kwargs):
version = request.version
ret = {
'code': 1000,
'msg': '请求成功',
'version': version
}
return JsonResponse(ret)

或者也可以全局配置, 不过使用URL解析的时候,需要在路由系统中正则匹配设置可用的版本,

REST_FRAMEWORK = {
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",
"VERSION_PARAM":'version', # 参数
}

<3>、测试

使用postman或者浏览器发送请求测试

http://127.0.0.1:8000/api/v1/,正确的获取版本号

5、反向解析URL

在django中也提供了一个url解析的函数reverse,不过在django rest framework中也有一个将reverse函数封装一层的接口可以进行url反向解析。

路由系统:加入namespace参数

from django.contrib import admin
from django.urls import path, include
from django.conf.urls import url urlpatterns = [
url(r'^api/', include('api.urls', namespace='api') ),
]

子路由系统:加入name参数

from django.conf.urls import url

from .views import VersionView

app_name = 'api' 

urlpatterns = [
url(r'^version/$', VersionView.as_view(), name='version'),
url(r'^(?P<version>[v1|v2]+)/$', VersionView.as_view(), name='version'),
]

示例一:参数携带版本

http://127.0.0.1:8000/api/version/?version=v1,发送请求

class VersionView(APIView):
versioning_class = QueryParameterVersioning def get(self, request, *args, **kwargs): version = request.version
url1 = request.versioning_scheme.reverse(viewname='api:version', request=request) url2 = reverse(viewname='api:version', kwargs=kwargs) ret = {
'code': 1000,
'msg': '请求成功',
'version': version,
'drf_url': url1,
'django_url': url2
}
return JsonResponse(ret)

使用postman返送请求

示例二:URL携带版本

http://127.0.0.1:8000/api/v1/,发送请求

class VersionView(APIView):
versioning_class = URLPathVersioning def get(self, request, *args, **kwargs): version = request.version
url1 = request.versioning_scheme.reverse(viewname='api:version', request=request) url2 = reverse(viewname='api:version', kwargs=kwargs) ret = {
'code': 1000,
'msg': '请求成功',
'version': version,
'drf_url': url1,
'django_url': url2
}
return JsonResponse(ret)

使用postman返送请求

这里有与drf的reverse在对django中的reverse函数进行封装的时候,获取了request.get_full_url(),并做了一个拼接,所以才会出现全部的url

三、源码分析

1、找到initial()方法

依旧从dispath方法进入源码,找到initial方法

2、进入initial()方法

这里调用了determine_version()方法,并拿到两个返回值并封装到request中。这时候request.version_scheme就是一个版本对象了

3、查看具体的determine_version()方法

4、默认的版本处理对象

可以在setting.py中配置之后,全局使用

5、drf提供的版本类

在url反向解析中,调用了request.versioning_scheme.reverse()中的reverse()方法,说明request.versioning_scheme返回的是一个版本对象,可以调用他的方法

BaseVersioning基类定义了三个接口

  • determine_version:返回版本
  • reverse:url反向解析使用
  • is_allowed_version:就是判断版本号是否合法

而上面示例使用的两个超类URLPathVersioning,QueryParameterVersioning其实也就是,重写了determine_version,和reverse两个方法。

四、总结

版本的获取方式有多种,在django rest framewok中也提供了一一对应的处理版本对象,可以根据自己的需要配置,或者继承重写接口使用。

配置也支持全局配置,和局部配置,在全局配置的时候,需要定义默认的版本号,以防万一。

在进行url反向解析的时候django rest framewok提供了一个更好的方式。

Django Rest framework 之 版本的更多相关文章

  1. Django REST framework之版本,解释器,序列化

    1 版本 2 解释器 3.序列化 1 版本 通过?后面传版本号有两种方法: 方法一 from django.shortcuts import render from rest_framework.vi ...

  2. Django rest framework 之版本

    一.通过 QueryParameterVersioning 获取版本 通过 QueryParameterVersioning 从 get 请求中获取版本信息: 1.新建 app,名为 api,Proj ...

  3. Django Rest framework 之 序列化

    RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...

  4. Django Rest framework 之 解析器

    RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...

  5. Django Rest framework 之 节流

    RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...

  6. Django Rest framework 之 权限

    django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) django res ...

  7. Django Rest framework 之 认证

    django rest framework 官网 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest fra ...

  8. Django Rest framework 之 视图

    RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...

  9. Django Rest framework 之 分页

    RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...

随机推荐

  1. samba服务配置(二)

    需求: 某公司销售部门提出一个文件共享需求,要求部门共享目录有三个,第一个共享目录所有销售部门人员都具有可读可写权限: 第二个共享目录所有销售人员只读权限,经理级别的销售人员具有可读可写权限:第三个共 ...

  2. 90 % Java 程序员被误导的一个性能优化策略

    我们经常看到一些 Java 性能优化的书或者理念,说不要在循环内定义变量,这样会占用过多的内存影响性能,而要在循环外面定义.接触 Java 这么久以来,相信很多 Java 程序员都被这种代码性能优化策 ...

  3. List和ArrayList的区别

    List是一个接口,而ListArray是一个类. ListArray继承并实现了List. 所以List不能被构造,但可以向上面那样为List创建一个引用,而ListArray就可以被构造. Lis ...

  4. 课程三(Structuring Machine Learning Projects),第二周(ML strategy(2)) —— 0.Learning Goals

    Learning Goals Understand what multi-task learning and transfer learning are Recognize bias, varianc ...

  5. spring cloud(断路器——初学五)

    Feign使用Hystrix 因为feign已经依赖了hystrix,所以可以直接使用,无需添加再次添加依赖. 1.使用@FeignClient注解中的fallback属性指定回调类 package ...

  6. Android Studio 快捷键总结(OS X)

      Action shortcut key 解释 跳转到类 cmd+0   跳转到文件 cmd+shift+0   跳转到函数 cmd+alt+0   最近打开的文件 cmd+e   最近编辑的文件 ...

  7. Android_性能优化转载

    胡凯 RSS Blog Archives Android Training in Chinese About Android性能优化典范 JAN 17TH, 2015 | COMMENTS 2015年 ...

  8. Maven的assembly插件实现自定义打包部署(包含依赖jar包)

    微服务必备 优点: 1.可以直接导入依赖jar包 2.可以添加插件启动 .sh 文件 3.插件的配置以及微服务的统一打包方式 1.首先我们需要在pom.xml中配置maven的assembly插件 & ...

  9. MongoDB——学习

    db.baidupic.distinct("source") db.baidupic.find({ "source":{ $nin:[ "百度图片&q ...

  10. 如何自定义CSS滚动条的样式?

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由前端林子发表 本文会介绍CSS滚动条选择器,并在demo中展示如何在Webkit内核浏览器和IE浏览器中,自定义一个横向以及一个纵向的 ...