博主要做一个记录请求api日志的事情。
声明:本文指定Django版本为1.8,其它版本实现方式自己网上搜!
@property
def body(self):
if not hasattr(self, '_body'):
if self._read_started:
raise RawPostDataException("You cannot access body after reading from request's data stream")
# Limit the maximum request data size that will be handled in-memory.
if (settings.DATA_UPLOAD_MAX_MEMORY_SIZE is not None and
int(self.META.get('CONTENT_LENGTH') or 0) > settings.DATA_UPLOAD_MAX_MEMORY_SIZE):
raise RequestDataTooBig('Request body exceeded settings.DATA_UPLOAD_MAX_MEMORY_SIZE.')
try:
self._body = self.read()
except IOError as e:
six.reraise(UnreadablePostError, UnreadablePostError(*e.args), sys.exc_info()[2])
self._stream = BytesIO(self._body)
return self._body
看这个意思说,别读过了,然后报错!why?
难道不行了吗?错!
你把这个值复制给另外一个变量就可以了:
re_request_body = getattr(request,'_body',request.body)
print re_request_body
你不能访问request.body,但是你可以访问复制过后的变量!还有,这个方法不适用在process_response方法中,我在process_request中是可以的!
Stack Overflow上有一个网友提到django restframework,我猜想,restframework它是继承Django的django.core.handlers.wsgi.WSGIRequest对象,他可以访问body,我想也是可以找到其它方法直接访问reqeust.body这个变量的,但是看了restframework源码,我一脸懵逼,能力有限,看不懂!最后,我附上国外友人提到的记录:
https://stackoverflow.com/questions/22740310/how-to-update-django-httprequest-body-in-middleware
最最后,我附上我能实现的代码:
import datetime
import random
class middleware_record_req_rsp(object):
def __init__(self):
nowTime = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
randomNum = random.randint(0,1000)
uniqueNum = str(nowTime) + str(randomNum)
self.flag = uniqueNum
def process_request(self,request):
if request.method == 'POST':
x_forward_for = request.META.get('HTTP_X_FORWARDED_FOR')
request_ip = x_forward_for.split(',')[0] if x_forward_for else request.META.get('REMOTE_ADDR')
request_user = request.META.get('USER')
re_request_body = getattr(request,'_body',request.body)
flag = self.flag
return None
def process_response(self,request,response):
if request.method == 'POST':
flag = self.flag
response_status_code = response.status_code
return response
最后看到一篇介绍中间件不错的好文章!
http://blog.csdn.net/wolaiye320/article/details/52035451
ps:相比较而言,浏览官网的信息才是最好的。但是能去GitHub,Stack Overflow上最好,尤其是Stack Overflow(最近公司的网日了
——————-分割线——————–
一个很有意思的问题出现了!我之前提到在中间件 process_response(request,response)中的request是拿不到request.body这个变量的,因为会报”you cannot access body after reading from request’s data stream”这种错误!我猜想,process_response(request,response)和process_request(request)中的request不一样吧!
结果,我测试了一下:
—————分割线——————
那么,在response的时候,是否可以修改response中的传给前端的值呢?官网如下解释:
it could alter the given response。Stack Overflow上有人问过:https://stackoverflow.com/questions/44112528/editing-response-contect-in-django-middleware
里面如下:
Response is already rendered in the middleware stage so you can't just change response.data, you need to rerender it or change rendered content directly.
class RequestLogMiddleWare(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
if isinstance(response, Response):
response.data['detail'] = 'I have been edited'
# you need to change private attribute `_is_render`
# to call render second time
response._is_rendered = False
response.render()
return response
The second approach is just change content directly, but in that case built in rest framework browser API will not work because template will not render properly.
import json
class RequestLogMiddleWare(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
if isinstance(response, Response):
response.data['detail'] = 'I have been edited'
response.content = json.dumps(response.data)
return response
然后我就是改掉content这个值,就可以实现更改了!