【问题标题】:Catch incorrectly %-encoded URLs in Django to return a custom "error 400" page在 Django 中捕获错误的 % 编码 URL 以返回自定义“错误 400”页面
【发布时间】:2013-01-16 05:10:36
【问题描述】:

有时,其他网站使用错误的百分比编码 URL 链接到我们的 Django 支持的网站。 Disqus.com 和 Twitter.com 确实有同样的问题,所以我们的用例没有什么特别之处:http://disqus.com/%C3A4。在此 URL 中,缺少第二个 %。有效的 URL 如下所示:http://disqus.com/%C3%A4

Django 返回一个空的错误 400(错误请求)页面。然而,我们想捕捉错误,而不是返回一个普通的非信息页面,我们希望至少向我们的用户展示我们的自定义 404 页面。甚至更好的是,我们想检查输入 URL 是否缺少 %-characters 或任何类似的东西来验证其格式。 MiddleWare/process_request 即使出现 400 错误也会被调用,所以我们确实有一个钩子来捕获错误。

我们想在我们的网站上解决这个问题。有没有最佳实践...?一个 handler400 会很棒 - 是否可以自己创建一个?

【问题讨论】:

  • 为什么不简单地通过拦截错误从前端代理重定向用户?
  • 如何使用不需要编码的干净 URL 来解决这个问题?
  • 我不明白关于代理的想法。你能再解释一下吗? ... Pixbay 有 20 种语言版本,(例如)中文和日文所有字符都需要正确的 UR 编码。我们这边的编码工作得很好。无论如何,“干净”一词并不完全正确,因为 %-encoding 确实是处理 URL 中国际字符的正确方法。
  • 到目前为止,我找到的唯一解决方案是在 Django 的处理程序“wsgi.py”中修补 WSGIRequest。问题归结为 Django 内部的 unicode 解码错误。

标签: django url encoding percent-encoding


【解决方案1】:

正如已在 Cathy 的回答中以评论的形式发布的那样,这确实很好,但在这种特殊情况下不起作用,我在这里发布我们当前的略显老套的解决方案作为另一个答案:

显然,这个错误不能在 Django 的 MiddleWares 中被覆盖。这是在 \django\core\handlers\wsgi.py 中的 WSGIHandler 内部触发的 UNICODE 解码错误。准确的说是

path_info = force_unicode(environ.get('PATH_INFO', u'/'))

在 WSGIRequest 内部,这是导致问题的原因。这基本上是 Django 的正确行为,但正如我的问题中所述,我们只是想向我们的用户展示比空的错误页面更有用的东西。因此,我们在将传入的 URL 请求传递给我们的 WSGIHandler 之前检查有效的 UNICODE 字符。这篇博文为我们指明了正确的方向:http://codeinthehole.com/writing/django-nginx-wsgi-and-encoded-slashes/

因此,我们在 wsgi.py 中重新路由无效 URL,如下所示:

os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'

import django.core.handlers.wsgi
_application = django.core.handlers.wsgi.WSGIHandler()

# for Django 1.7+
# from django.core.wsgi import get_wsgi_application
# _application = get_wsgi_application()

from django.utils.encoding import force_unicode
def application(environ, start_response):
    try:
        path_info = force_unicode(environ.get('PATH_INFO', u'/'))
    except:
        environ['PATH_INFO'] = u'/'
    return _application(environ, start_response)

子类化 WSGHandler 也应该有效。在此示例中,我们只是将无效 URL 重定向到我们的站点根目录“/”。但是您也可以重定向到任何自定义错误页面 URL,或者您可以尝试清理您的 URL ...它适用于我们,但也许有更好的解决方案。

【讨论】:

    【解决方案2】:

    在您的模板中创建 404.html,然后将其放入您的 urls.py

    #handle the errors    
    from django.utils.functional import curry
    from django.views.defaults import *
    
    handler404 = curry(page_not_found, template_name='404.html')
    
    You can also handle other errors like this:
    handler500 = curry(server_error, template_name='500.html')
    handler403 = curry(permission_denied, template_name='403.html')
    

    处理任何类型的错误。你会在这里得到一个想法。

    https://github.com/Roejames12/django-error-pages
    

    【讨论】:

    • 问题是:我们需要一个handler400,这在Django中是不存在的。 handler403、404 和 500 确实存在并且可以适当地使用......奇怪的是,我什至看不到 Django 如何处理现有的处理程序,否则我会尝试将它们复制和修改为新的自定义处理程序......有什么想法吗?
    • 使用它处理任何类型的错误,github.com/Roejames12/django-error-pages
    • 谢谢凯茜! +1 伟大的提示。但是,django-error-pages 没有捕捉到这个错误。与此同时,我们提出了一个有点丑陋的解决方案。该错误在 Django 的 WSGIHandler 中引发。似乎没有办法解决这种硬编码行为。中间件被简单地覆盖,这就是 django-error-pages 在这里不起作用的原因。基于以下脚本,我们现在通过子类化 Django 的 WSGIHandler 解决了这个问题:我们在无效 URL 到达处理程序之前对其进行修改。 codeinthehole.com/writing/django-nginx-wsgi-and-encoded-slashes
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-05
    相关资源
    最近更新 更多