转:django中session的实现机制
转:www.jianshu.com
要理解session,首先要搞清楚cookie的概念。由于http是无状态的,服务器不能记住用户的信息状态,因此若由同一个客户端发起的多条请求,服务器不能辨别这些请求来自哪个用户。http无状态的限制为web应用程序的设计带来了许多不便,购物网站中的"购物车"功能就是一个很好的例子,当用户把商品放进购物车后,客户端必须要保存购物车的状态,否则当用户下次浏览网站时,购物车拥有的商品状态便不复存在。客户端和服务器必须有通信的媒介,方便服务器追踪客户端的状态,于是cookie技术应运而生,cookie是服务器产生的一段随机的字符串,发送给客户端,随后客户端便保存cookie,并使用这个cookie附带进后续的请求,以下是cookie设置的详细流程:
1、客户端发起一个请求连接(如HTTP GET)
2、服务器在http响应头上加上Set-Cookie,里面存放字符串的键值对
3、客户端随后的http请求头加上cookie首部,它包含了之前服务器响应中设置cookie的信息
根据这个Cookie首部的信息,服务器便能记住当前用户的信息
再来看看在python中是如何设置Cookie的:
from BaseHTTPServer import HTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
import Cookie
class MyRequestHandler(SimpleHTTPRequestHandler):
def do_GET(self);
content = "<html><body>Path is:%s</body></html>"%self.path
self.send_response(200)
self.send_header('Content-type','text/html')
self.senf_header('Content-length',str(len(content)))
cookie = Cookie.SimpleCookie()
cookie['id'] = 'some_value_42'
self.wfile.write(cookie.output())
self.wfile.write('\r\n')
self.end_headers()
self.wfile.write(content)
server = HTTPServer(('',59900),MyRequestHandler)
server.serve_forever()
查看服务器端的http响应头,会发现以下字段:
Set-Cookie:id=some_value_42
而在django中,可以用如下的方式获取或设置Cookie:
def test_cookie(request):
if 'id' in request.COOKIES:
cookie_id = request.COOKIES['id']
return HttpResponse('Got cookie with id=%s'%cookie_id)
else:
resp = HttpPesponse('No id cookie!sending cookie to client')
resp.set_cookie('id','some_value_99')
return resp
Django通过一系列的包装使得封装Cookie的操作变得更加简单,那么它在其中是怎么实现cookie的读取的呢,下面来窥探原理:
def _get_cookies(self):
if not hasattr(self,'_cookies'):
self._cookies = http.parse_cookie(self.environ.get('HTTP_COOKIE',''))
return self._cookies
可以看出,获取cookie的操作用了Lazyinitialization(延迟加载)的技术,因为如果客户端不需要用到cookie,这个过程只会浪费不必要的操作
再来看parse_cookie的实现:
def parse_cookie(cookie):
if cookie == '':
return {}
if not isinstance(cookie,Cookie.BaseCookie):
try:
c = SimpleCookie()
c.load(cookie,ignore_parse_errors=True)
except Cookie.CookieError:
return {}
else:
c= cookie
cookiedict = {}
for key in c.keys():
cookieddict[key] = c.get(key).value
return cookiedict
它负责解析Cookie并把结果集成到一个dict(字典)对象中,并返回字典。而设置cookie的操作则会被WSGIHandler执行
注意:django的底层实现了WSGI的接口(如WSGIRequest,WSGIServer等)
Session
前面介绍了Cookie的作用,有了Cookie,为什么还需要Session呢?其实很多情况下,只使用Cookie便能完成大部分目的。但是人们发现,只使用Cookie往往是不够的,考虑用户登录信息或一些重要的敏感信息,用Cookie会把信息保存到本地,因此信息的安全性可能受到威胁。Session的出现和好解决了这个问题,Session与Cooike类似,但他们最明显的区别是,Session会将信息保存到服务器端,客户端需要一个session_id,它是一段随机的字符串,类似身份证的功能,从服务器端根据这个凭证来获取信息。而这个session_id通常保存在Cookie中的,换句话说,Session的信息传递一般要借用到Cookie,如果Cookie被禁用,它则可能通过url加上query string来添加session_id
下面来看一个简单的session应用例子
def test_count_session(request):
if 'count' in request.session:
request.session['count'] +=1
return HttpResponse('new count=%s'%request.session['count'])
else:
request.session['count']=1
return HttpResponse('No count in session.Setting to 1')//可以用来写被访问了多少次
它用session实现了一个计数器,当每一个请求到来时,就为计数器加一,把新的结果更新到session中
查看http的响应头,会得到类似下面的信息
Set-Cookie:sessionid=q99e9e9e992939383838;
exoires = Thu,07-Jul-2011 04:16:28 GMT;
Max-Age=1209600
Path=/
里面包含了session_id以及过期时间等信息
那么服务器端是如何保存session呢?
在django中,默认会把session保存在setting指定的数据库中,除此之外,也可以通过指定session engine,使session保存在文件(file),内存(cache)中
如果保存在数据库中,django会在数据库中创建一个如下的session表
CREATE TABLE "django_session"(
'session_key vachar(40) NOT NULL PRIMARY KEY,
'session_data' text NOT NULL,
'expire_date' datetime NOT NULL
);
session_key是放置在cookie中的id,它是唯一的,而session_data则存放序列化后的session数据字符串。
通过session_key可以在数据库中取得这条session的信息:
from django.contrib.session.models import Session
sess = Session.objects.get(pk='a9sjsjsjsjjs')
print(sess.session_data)
print(sess.get_decoded)
输出
ZmEy...
{'count':6}
回看第一个例子,我们是通过request.session来获取session的,为什么请求对象会附带一个session对象呢,这其中做了什么呢?
这就引出了下面要说的django里的中间件技术
session middleware
关于中间件,django book是这样解释的:
django的中间件框架,是django处理请求和响应的一套钩子函数的集合
我们看传统的django师徒模式一般是这样的:http请求->view->http响应,而加入中间件框架后,则变为:http请求->中间件处理->app->中间件处理->http响应
而在django中这两个处理分别对应process_request和process_reponse函数,这两个钩子函数将会在特定的时候触发
直接看SessionMiddleware可能更清晰一些
class SessionMiddleware(object):
def __init__(self):
engine = import_module(settings.SESSION_ENGINE)
self.SessionStore = engine.SessionStore
def process_request(self,request):
session_key= request.COOKIES.get(settings.SESSION_COOKIE_NAME)
request.session = self.SessionStore(session_key)
def process_response(self,request,response):
'''
If request.session was modifid,or if the configuration is to save the session every time,save the changes and set a session cookie or delete the session cookie if the session has been emptied
'''
try:
accessded = request.session.accessed
modified = request.session.modified
empty = request.session.is_empty()
except AttributeError:
pass
else:
#First check if we need to delete this cookie.
#The session should be deleted only if the session is entirely empty
if settings.SESSION_COOKIE_NAME in request.COOKIES and empty:
response.delete_cookie(setting.SESSION_COOKIE_NAME,domain=setting.SESSION_COOKIE_DOMAIN)
else:
if accessed;
patch_vary_headers(response)
if (modified or settings.SESSION_SAVE_EVERY_REQUEST) and not empty:
if request.session.get_expire_at_browser_close():
max_age = None
expired = None
else:
max_age = request.session.get_expiry_age()
expired_time = time.time()+max_age
expires = cookie_date(expires_time)
#Save the session data and refresh the client cookie
#skip session save for 500 responses,refs #3883
if response.status_code != 500:
try:
request.session.save()
except UpdateError:
#The user is now logged out;redirecting to same page will resilt in a redirect to the login pagr if required
return redirect(request.path)
response.set_cookie(settings.SESSION_COOKIE_NAME,request.session.session_key,max_age=max_age,expires=expires,domain=settings.SESSION_COOKIE_DOMAIN,path = settings.SESSIONG_COOKIE_PATH,secure=setting.SESSION_COOKIE_SECURE or None,httponly=settings.SESSION_COOKIE_HTTPONLY or None)
return response
在请求过来后,SessionMiddleware的process_request在请求取出session_key,并把一个新的session对象赋给request.session,而在返回响应时,process_response则判断session是否被修改或过期,来更新session的信息
Django用户认证中的Session
在django中,用下面的方法来验证用户是否登录是常见的事情
def test_user(request):
user_str = str(request.user)
if request.user.is_authenticated():
return HttpResponse('%s is logged in' %user_str)
else:
return HttpResponse('%s is not logged in'%user_str)
其实request.user的实现也借助到了session
在这个例子中,成功登录后,session表会保存类似下面的信息,里面记录了用户的id,以后进行验证时,便会到这个表中获取用户的信息。
{'_auth_user_id': 1, '_auth_user_backend': 'django.contrib.auth.backends.ModelBackend'}跟上面提到的Session中间件相似,用户验证也有一个中间件:AuthenticationMiddleware,在process_request中,通过request.class.user = LazyUser()在request设置了一个全局的可缓存的用户对象。
class LazyUser(object):
def __get__(self,request,obj_type=None):
if not hasattr(request,'_chached_user'):
from django.contrib.auth import get_user
request_._cached_user = get_user(request)
return request._cached_user class AuthenticationMiddleware(object):
def process_request(self,request):
request.__class__.user = LazyUser()
return None
在get_user里,会在检查session中是否存放了当前用户对应的user_id,如果有,则通过id在model查找相应的用户返回,否则返回一个匿名的用户对象(AnonymousUser)
def get_user(request):
from django.contrib.auth.models import AnonymousUser
try:
user_id = request.session[SESSION_KEY]
backend_path = request.session[BACKEND_SESSION_KEY]
backend = load_backend(backend_path)
user = backend.get_user(user_id) or AnonymousUser()
except KeyError:
user = AnonymousUser()
return user
Django中的Session实现
Django使用的Session默认都继承于SessionBase类里,这个类实现了一些session操作方法,以及hash,decode,encode等方法
class SessionBase(object):
'''
Base class for all Session classes.
'''
def __init__(self,session_key=None):
self._session_key = session_key
self.accessed = False
self.modified = False
self.serializer = import_string(settings.SESSION_SERIALIZER)
说的更直白一些,其实django中的session就是一个模拟dict的对象,并实现了一系列的hash和序列化方法,默认持久化在数据库中(有时候也可能由于为了提高性能,用redis之类的内存数据库来缓存session)。
转:django中session的实现机制的更多相关文章
- 在Django中Session的那点事!
1.session是什么 首先引入度娘的解释:Session:在计算机中,尤其是在网络应用中,称为“会话控制”.Session 对象存储特定用户会话所需的属性及配置信息.这样,当用户在应用程序的 We ...
- php中session的生成机制、回收机制和存储机制探究
1.php中session的生成机制 我们先来分析一下PHP中是怎么生成一个session的.设计出session的目的是保持每一个用户的各种状态来弥补HTTP协议的不足(无状态).我们现在有一个疑问 ...
- php中session的运行机制
在PHP中session默认是以文件的形式存储于服务器的 而客户端和服务端则是通过session_id来完成握手的,默认情况下PHP会将session_id存储于cookie中,用户每次请求时该ses ...
- 简单操作django中session和cookie
cookie 1.会话技术 2.客户端的会话技术( 数据库保存在浏览器上) 3.问题导致原因: 在web应用中,一次网络请求是从request开始,到response结束,跟以后的请求或者跟其他请求没 ...
- Django中session的基础了解
基于cookie做用户验证时:敏感信息不适合放在cookie中 session依赖cookie session原理 cookie是保存在用户浏览器端的键值对 session是保存在服务器端的键值对 s ...
- Django中Session
Django中默认支持Session,其内部提供了5种类型的Session供开发者使用: ·数据库(默认) ·缓存 ·文件 ·缓存+数据库 ·加密cookie (1)数据库中的Session Djan ...
- Tomcat中session的管理机制
1. 请求过程中的session操作: 简述:在请求过程中首先要解析请求中的sessionId信息,然后将sessionId存储到request的参数列表中.然后再从 request获取s ...
- django中session的存储位置
django-session 存放位置 设置session的保存位置,有三种方法: 保存在关系数据库(db) 保存在缓存数据库(cache) 或者 关系+缓存数据库(cache_db) 保存在文件系统 ...
- Django中orm的惰性机制
那么首先要知道什么是ORM 专业化的角度来说:叫对象关系映射(Object-Relation Mapping)是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术. 那具体ORM是什么呢?:( ...
随机推荐
- Ubuntu 14.04上架IPSec+L2TP的方法
最简单的方法是使用脚本一步一步地进行配置.我用的是philplckthun写的脚本,修改了一下获取服务器IP的方法:脚本文件. 在ubuntu下运行: sh setup.sh 配置配置完成后,服务器端 ...
- wyx20162314实验报告二
北京电子科技学院BESTI实验报告 课程:程序设计与数据结构 班级: 1623 姓名: 王译潇 学号:20162310 指导教师:娄佳鹏老师.王志强老师 实验日期:2017年3月26号 实验密级: 非 ...
- 转一篇Git代码回滚技巧
转 https://github.com/geeeeeeeeek/git-recipes/wiki/5.2-代码回滚:Reset.Checkout.Revert的选择
- Linux之间配置免秘钥访问
环境说明 [root@localhost1 ~]# cat /etc/redhat-release CentOS release 6.5 (Final) [root@localhost1 ~]# un ...
- usb gadget虚拟串口【转】
本文转载自:https://blog.csdn.net/luckywang1103/article/details/61917916 配置 配置好之后编译重新烧写到开发板,发现出现了/dev/ttyG ...
- tp添加分页
//分页开始 $count=M('article')->where($condition)->count(); $p = intval($p) > 0 ? $p : 1; $page ...
- spark学习(RDD案例实战)
练习0(并行化创建RDD) 先启动spark-shell 通过并行化生成rdd scala> val rdd1 = sc.parallelize(List(63,45,89,23,144,777 ...
- Kubernetes学习整理
修改镜像仓库 官方提供的时google源,显然是无法使用的.这里需要改成国内的源 cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kube ...
- virtio,vhost 和vhost-user
随着qemu2.1的发布,可以看到,qemu支持了vhost-user.从介绍可以看出,这是把原来vhost-backend从kernel移到了userspace,这和原来virtio架构有什么区别呢 ...
- 谈谈你对Glide和Picasso他们的对比的优缺点
1.Picasso和Glide的withi后面的参数不同 Picasso.with(这里只能传入上下文) . Glide.with,后面可以传入上下文,activity实例,FragmentA ...