关于django中间件使用的踩坑经历

栏目: Python · 发布时间: 7年前

内容简介:这个之前本地写的那个django测试项目说起,那时候写了个练手的项目,目的是为了起因是当我在自强学堂的django课堂上,看到了有一个demo,这个demo具体实现的效果就是当网站在正式环境上运行的时候,为了安全起见,将DEBUG改为False(关闭调试模式),但是导致网站发生错误无法查看错误详情。所以demo主要的就是写一个

背景

这个之前本地写的那个django测试项目说起,那时候写了个练手的项目,目的是为了 熟悉总结django2.0和django1.8的区别 。不试不知道,一试就发现了许许多多的坑以及bug,把这些坑以及bug解决完了之后,打算写篇文章记录下我遇到的问题以及解决方法和思路。

起因

起因是当我在自强学堂的django课堂上,看到了有一个demo,这个demo具体实现的效果就是当网站在正式环境上运行的时候,为了安全起见,将DEBUG改为False(关闭调试模式),但是导致网站发生错误无法查看错误详情。

所以demo主要的就是写一个 通过中间件识别身份 的方式,如果是管理员则可以看到 网站错误详情 ,如果是普通访问者或者游客则 返回的是简单的错误码

详细设计

设计思路

中间件识别登录身份,判断是否为管理员,如果是管理员的话,当网站出现错误的时候则会显示错误详情;如果是普通游客的话则单纯显示错误码,不显示详情。

关于中间件

我整理了一下有关django的中间件知识,这里大概聊一下,以后有机会单独的写篇文章总结一下。首先我们要明白什么是中间件:

这里先引用官方文档的一段话:

Middleware is a framework of hooks into Django’s request/response processing. It’s a light, low-level “plugin” system for globally altering Django’s input or output.

  • 简而言之,Middleware就是能够修改Django中 response/request对象的钩子 ,我们可以利用Middleware来实现在请求到达 view视图函数 前的一些操作。
  • 举个最简单的例子: 一个管理后台判断用户是否登录 ,就是判断 request对象中的用户 ,如果对象中的用户是不存在的,则重定向到登录页面。

中间件处理流程

大概了解了一下中间件是什么东西,可以用来做什么,我们大致分析一下中间件的处理流程。

关于django中间件使用的踩坑经历

相信上图在很多django教程中看到过,上图都是Django中内置的一些中间件,这些中间件都放在Django中 settings.py 文件中的 MIDDLEWARE_CLASSES(django 2.0版本后放在MIDDLEWARES上)

然后在http请求阶段,在view调用之前了,django会将 MIDDLEWARE_CLASSES 中的中间件都执行一遍。而这里面的主要的几个钩子函数:

  • process_request()、process_view() 会从上到下挨个执行一遍;
  • process_exception()、process_template_response()、process_response() 则会从下到上挨个执行一遍。
    具体这几个函数作用,以及django内置中间件分别负责什么作用单独会另外写篇文章总结。
    这里的主要使用到 process_exception() 钩子,这个钩子函数只有当view抛出异常的时候会触发,所以很适合返回网站的错误详情。

具体实现

终于到实操环节了,思路上面提到过了,这里具体代码实现的逻辑:

用户通过登录界面登录到平台,通过内置的 auth模块 保存用户登录到会话中。

如果网站出现错误信息时,这时异常抛到自己的中间件时,捕获views视图函数抛出的异常,判断request中的user对象是否为超级管理员,如果是的话,则返回一个错误详细响应到前端,不是的话正常返回500错误码。

  • 以下是views.py中关于用户登录模块,具体登录请求会提交到这里:

    def login(request):
    if request.method == 'POST':
        user_name = request.POST['user_name']
        user_password = request.POST['user_password']
    
        user = auth.authenticate(username=user_name, password=user_password)
        if user is not None:
            auth.login(request, user)
            return redirect('/index')
        else:
            return render(request, 'login.html', {'login_error': '登录失败,密码>错误'})
    return render(request, 'login.html')
  • 中间件middleware.py具体代码(具体位置放在app应用下):
from django.views.debug import technical_500_response
import sys

class UserBasedExceptionMiddleware(object):
    def process_exception(self, request, exception):
        if request.user.is_superuser:
            return technical_500_response(request, *sys.exc_info())
  • settings.py修改MIDDLEWARE_CLASSES:
    MIDDLEWARE_CLASSES = [
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'app.middleware.UserBasedExceptionMiddleware',
    ]

* 这样就能实现返回网站错误信息啦:

关于django中间件使用的踩坑经历

做到这里想必是做完了,但是我更想谈谈我在这过程遇到两个问题,在这两个问题里可能花费的时间更多。

遇到的问题

解决DEBUG=False下,静态资源访问出现404

由于将DEBUG模式设置 False 之后,重新启动项目后,发现所有的静态文件都无法访问。

关于django中间件使用的踩坑经历

查了一下官方文档,官方文档给出的解释就是,在开发过程中,django会提供 django.contrib.staticfiles 帮助管理静态文件,而开启这一功能,除了 需要包含在INSTALL_APPS之外 ,还需要将 DUBUG模式改为True

所以略微分析,大概就知道我们静态文件404访问不到的原因了,简单来说就是 django提供给我们的静态文件路由功能不能用了 ,导致404错误。

当然官方贴心的给出了额外的建议:

  1. 使用serve()视图提供静态资源访问服务。
  2. 通过Nginx、Apache等代理静态资源。

而对于在生产环境下,官方更推荐的是 第二种方法 ,原因无非就两个:

  1. django提供的serve()视图仅用于开发辅助使用,不适合生产使用。
  2. Nginx处理静态资源有着更强的性能优势。

解决过程

这里我们就先通过上面提到第一种方法来解决“静态资源404的问题”。

而关于Django和Nginx部署Django项目的,之前在一篇文章里介绍过,大家有兴趣可以去看看: https://blog.51cto.com/mbb97/2151933

  • 解决这一问题其实很简单,直接修改 urls.py ,直接在 urlpatterns 列表下增加多一段代码,匹配静态资源请求路径,调用 django内置静态资源处理方法serve() ,大功告成。
from django.contrib import admin
from django.views.static import serve
from django.urls import path,re_path

urlpatterns = [
     path('admin/', admin.site.urls),
]
if not settings.DEBUG:
    urlpatterns += [
        re_path(r'^static/(?P<path>.*)$', serve, {'document_root': 'static', }),
    ]

* 重启django项目,大功告成,第一个问题解决

关于django中间件使用的踩坑经历

中间件不适配django2.0

我把这个中间件文件复制到另外一个项目中,打算一劳永逸,没想到竟然出错了:

关于django中间件使用的踩坑经历

首先我检查的就是 版本 的问题,我看了一下刚刚中间件成功的那个项目是属于 django1.8.2版 本,而如今报错的项目没想到是 django2.0 版本。

我查了官方文档,以下是官方文档的解释,有兴趣的可以了解以下:

https://docs.djangoproject.com/zh-hans/2.2/topics/http/middleware/

而参考官网给出的解决方法,就是通过Django提供的 django.utils.deprecation.MiddlewareMixin 类,它能够轻松兼容新版的 MIDDLEWARE和旧版的MIDDLEWARE_CLASSES

  • 以下是示例代码,修改中间件能够轻松兼容Django新版本和旧版本:
from django.views.debug import technical_500_response
import sys
try:
    from django.utils.deprecation import MiddlewareMixin
except:
    MiddlewareMixin = object

class UserBasedExceptionMiddleware(MiddlewareMixin):
    def process_exception(self, request, exception):
        if request.user.is_superuser:
            return technical_500_response(request, *sys.exc_info())
  • 重启项目,没有报错:

    关于django中间件使用的踩坑经历
  • 问题解决,管理员用户能够看到网站错误信息:

关于django中间件使用的踩坑经历

总结

没想到一个小小的中间件功能实现竟然途中遇到了这么多问题,但是在遇到问题的过程中排查问题的方向都是大致正确的,说起不足的地方还是对于Django的整体框架知识不够扎实。

由于Django上很多东西都是等到需要用的时候,才会去查找资料,这也导致很多问题不能第一时间反应解决。所以对 于Django新版本和旧版本之间的区别 没有及时的整理,以及 类似中间件重要的知识点 没有及时归纳。

以后尽量抽时间整理一下Django的框架知识,当然工作学习过程中踩到的坑能够分享,也是对自己另外的一种学习提升。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Haskell School of Expression

The Haskell School of Expression

Paul Hudak / Cambridge University Press / 2000-01 / USD 95.00

Functional programming is a style of programming that emphasizes the use of functions (in contrast to object-oriented programming, which emphasizes the use of objects). It has become popular in recen......一起来看看 《The Haskell School of Expression》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具