最近在做django 项目,重温动态语言的魅力
文章目录
Django cors跨域解决
from django.utils.deprecation import MiddlewareMixin
class CorsMiddleware(MiddlewareMixin):
def process_response(self, request, response):
response['Access-Control-Allow-Origin'] = "*"
response['Access-Control-Allow-Headers'] = "*"
response['Access-Control-Allow-Credentials'] = "true"
response['Access-Control-Allow-Methods'] = "POST, OPTIONS, GET, PUT"
return response
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'corsheaders.middleware.CorsMiddleware',
'AIService.cors_middleware.CorsMiddleware'
]
理解WSGI 接口
根据Python的惯例,Django不是一个完整的Web后端框架,它只负责开发WSGI应用程序 ,在生产环境中Django应用应当与一个WSGI服务器配套,由WSGI服务器负责网络通讯部分。
WSGI,全称 Web Server Gateway Interface,或者 Python Web Server Gateway
Interface ,是为 Python语言定义的Web服务器和Web应用程序之间的一种简单而通用的接口。Gateway,也就是网关。网关的作用就是在协议之间进行转换。
它主要负责http协议的解析和组装,web服务器把解析好的所有数据发送给web应用(django),web应用决定返回哪个html页面发送给web服务器,web服务器组装好后在发送给客户端.
uWSGI Web服务器, 它与WSGI协议的关系
uWSGI是一个Web服务器,它实现了WSGI协议、uwsgi、http等协议。Nginx中HttpUwsgiModule的作用是与uWSGI服务器进行交换。
wsgi server (比如uWSGI) 要和 wsgi application(比如django )交互,uwsgi需要将过来的请求转给django 处理,那么uWSGI 和 django的交互和调用就需要一个统一的规范,这个规范就是WSGI WSGI(Web Server Gateway Interface)
uwsgi协议
uwsgi是服务器和服务端应用程序的通信协议,规定了怎么把请求转发给应用程序和返回
如何区分项目配置(生产、测试)
本地调试: 终端指定 settings
python3 manage.py runserver --settings=AIService.debug_settings
部署: Dockerfile中指定不同的wsgi.py文件来区分
CMD ["gunicorn", "-c", "gunicorn.conf.py", "AIService.debug_wsgi"]
CMD ["gunicorn", "-c", "gunicorn.conf.py", "AIService.wsgi"]
如何在Django中启动一个辅助线程工作?
answer: Try to call your init code from end of wsgi.py
file. It will be executed once at start of server.
example: 启动一个mq消费线程工作
import django
from django.core.handlers.wsgi import WSGIHandler
def get_wsgi_application():
"""
The public interface to Django's WSGI support. Return a WSGI callable.
Avoids making django.core.handlers.WSGIHandler a public API, in case the
internal WSGI implementation changes or moves in the future.
"""
django.setup(set_prefix=False)
# 把主进程中的kafka consumer线程放入启动过程中(即放入gunicorn的master进程中),
# 以使用gunicorn的preload参数控制这些线程的启动个数。
from utils.mq import consumer, start_consumer_daemon
start_consumer_daemon()
return WSGIHandler()
开一个线程
def start_consumer_daemon():
try:
for _ in range(1):
t = threading.Thread(target=consumer)
t.setDaemon(True)
t.start()
except Exception as e:
logger.error(e)
https://stackoverflow.com/questions/14630467/starting-a-simple-python-thread-on-django-init
Django中实现自定义中间件?
from django.utils.deprecation import MiddlewareMixin
from utils.key import gen_appraiser_token_key
from django.http.response import HttpResponse
from utils.redis import r
from .models import *
RequestMetaUserKey = "HTTP_USERID"
class AppraiserAuth(MiddlewareMixin):
def process_request(self, request):
token = request.META.get("HTTP_AUTHORIZATION")
if token is None:
return HttpResponse('Unauthorized', status=401)
key = gen_appraiser_token_key(token)
id = r.connection.get(key)
if not id:
return HttpResponse('errmsg', status=401)
appraiser = Appraiser.objects.filter(pk=int(id), status="1").first()
if not appraiser:
return HttpResponse('errmsg', status=401)
request.META[RequestMetaUserKey] = appraiser.id
def process_response(self, request, response):
return response
from django.utils.decorators import decorator_from_middleware
@api_view(["POST"])
@decorator_from_middleware(AppraiserAuth)
def appraiser_detail(request):
"""h5请求"""
pb_req = h5_manual_appraisal_pb.TSManualAppraiserDetailRequest()
pb_res = h5_manual_appraisal_pb.TSManualAppraiserDetailResponse()
# 校验请求参数
try:
req_data = pb_to_dict(request.body, pb_req)
except Exception as e:
logger.warning(f"pb to dict failed:{e}")
res_data = {
"errorCode": 10022,
"errorMsg": "Invalid params",
}
return HttpResponse(dict_to_pb(res_data, pb_res), content_type=PB_CONTENT_TYPE)
moaid = req_data.get("moaid")
invalid_params = []
if not moaid:
invalid_params.append("moaid")
if invalid_params:
res_data = {
"errorCode": 10022,
"errorMsg": f"Invalid params: {invalid_params}",
}
return HttpResponse(dict_to_pb(res_data, pb_res), content_type=PB_CONTENT_TYPE)
appraiser_id = request.META.get(RequestMetaUserKey)
proto与dict互转
from google.protobuf.json_format import MessageToDict, ParseDict
PB_CONTENT_TYPE = "application/x-protobuf"
def pb_to_dict(pb_str, pb):
pb.ParseFromString(pb_str)
return MessageToDict(pb, preserving_proto_field_name=True)
def dict_to_pb(pb_dict, pb):
ParseDict(pb_dict, pb)
return pb.SerializeToString()
res_data = {
"errorCode": 0,
"errorMsg": "Success",
}
try:
pb_res_data = dict_to_pb(res_data, pb_res)
except Exception as e:
logger.warning(f"dict to pb failed:{e}\n dict:{res_data}")
res_data = {
"errorCode": 10026,
"errorMsg": "Serialize response to protobuf failed",
}
return HttpResponse(dict_to_pb(res_data, pb_res), content_type=PB_CONTENT_TYPE)
return HttpResponse(pb_res_data, content_type=PB_CONTENT_TYPE)