【问题标题】:HTTP Parameters not being sent in Apache 2.4 breaking functionalityHTTP 参数未在 Apache 2.4 中断功能中发送
【发布时间】:2014-09-03 16:26:16
【问题描述】:

让我们从一些背景开始。我有一个 3 层系统,在 django 中实现了一个 API,在 Apache2 服务器上运行 mod_wsgi

今天我决定将运行在DigitalOcean 的服务器从 Ubuntu 12.04 升级到 Ubuntu 14.04。没什么特别的,只是 Apache2 也更新到了 2.4.7 版本。在浪费了一天的大部分时间弄清楚 they actually changed the default folder from /var/www to /var/www/html 破坏功能之后,我决定测试我的 API。没有接触任何一行代码,我的一些功能就无法正常工作。

我将使用其中一个较小的函数作为示例:

# Returns the location information for the specified animal, within the specified period.
@csrf_exempt # Prevents Cross Site Request Forgery errors.
def get_animal_location_reports_in_time_frame(request):
    start_date = request.META.get('HTTP_START_DATE')
    end_date = request.META.get('HTTP_END_DATE')
    reports = ur_animal_location_reports.objects.select_related('species').filter(date__range=(start_date, end_date), species__localizable=True).order_by('-date')
    # Filter by animal if parameter sent.
    if request.META.get('HTTP_SPECIES') is not None:
        reports = reports.filter(species=request.META.get('HTTP_SPECIES'))

    # Add each information to the result object.
    response = []
    for rep in reports:
        response.append(dict(
            ID=rep.id,
            Species=rep.species.ai_species_species,
            Species_slug=rep.species.ai_species_species_slug,
            Date=str(rep.date),
            Lat=rep.latitude,
            Lon=rep.longitude,
            Verified=(rep.tracker is not None),
        ))
    # Return the object as a JSON string.
    return HttpResponse(json.dumps(response, indent = 4))

经过一些调试,我观察到request.META.get('HTTP_START_DATE')request.META.get('HTTP_END_DATE') 正在返回None。我尝试了很多客户端,从 REST 客户端(例如 PyCharm 和 RestConsole for Chrome 中的客户端)到通常与 API 通信的 Android 应用程序,但结果是一样的,这两个参数没有被发送。

然后我决定测试是否正在发送其他参数,令我惊恐的是,它们确实如此。在上述函数中,request.META.get('HTTP_SPECIES') 将具有正确的值。

在对名称进行了一番摆弄之后,我观察到 ALL 标题中包含 _ 字符的参数不会进入 API。

所以我想,很酷,我将使用 - 而不是 _ ,这应该可行,对吧?错误的。 -_ 的形式到达 API!

此时我完全迷惑了,所以我决定找出罪魁祸首。我使用 django 开发服务器运行 API,通过运行:

sudo python manage.py runserver 0.0.0.0:8000

当使用相同的客户端发送相同的参数时,它们会被 API 很好地拾取!因此,django 没有导致这个,Ubuntu 14.04 没有导致这个,唯一可能导致它的是 Apache 2.4.7!

现在将默认文件夹从/var/www 移动到/var/www/html,从而破坏了功能,所有这些都是(在我看来)非常愚蠢的理由已经够糟糕了,但这太过分了。

有没有人知道这里实际发生了什么以及为什么?

【问题讨论】:

  • 你的 .htaccess 是什么?

标签: apache http ubuntu apache2 apache2.4


【解决方案1】:

这是 Apache 2.4 中的一个变化。

这是来自Apache HTTP Server Documentation Version 2.4

MOD CGI, MOD INCLUDE, MOD ISAPI, ... 将标头转换为环境变量比以前更严格 通过标头注入减轻一些可能的跨站点脚本攻击。包含无效字符的标头 (包括下划线) 现在被静默删除。 Apache 中的环境变量(第 81 页)有一些指示 关于如何解决需要此类标头的损坏的旧客户端。 (这会影响所有使用 这些环境变量。)

– 第 11 页

出于可移植性的原因,环境变量的名称只能包含字母、数字和下划线字符。此外,第一个字符可能不是数字。 在传递给 CGI 脚本和 SSI 页面时,不符合此限制的字符将被替换为下划线

– 第 86 页

换句话说,一个相当显着的变化。因此,您需要重写您的应用程序,以便发送破折号而不是下划线,而 Apache 会反过来替换下划线。

编辑

似乎有办法解决这个问题。如果您在 apache.org 上查看this document,您可以看到您可以通过将您的foo_bar 的值放入一个名为foo-bar 的新变量中来修复它在.htaccess foo_bar 来自 Apache。请参见下面的示例:

SetEnvIfNoCase ^foo.bar$ ^(.*)$ fix_accept_encoding=$1
RequestHeader set foo-bar %{fix_accept_encoding}e env=fix_accept_encoding

唯一的缺点是您必须为每个标头制定规则,但您不必对客户端或服务器端的代码进行任何更改。

【讨论】:

  • 虽然我完全不赞成他们的所作所为,但您的回答说明了正在发生的事情。谢谢!
  • 这也让我感到困惑。奇怪的是,这似乎是一个很大的变化。
【解决方案2】:

你确定 Django 也没有升级吗?

https://docs.djangoproject.com/en/dev/ref/request-response/

除了上面给出的 CONTENT_LENGTH 和 CONTENT_TYPE 之外,请求中的任何 HTTP 标头都通过将所有字符转换为大写、用下划线替换任何连字符并在名称中添加 HTTP_ 前缀来转换为 META 键。因此,例如,一个名为 X-Bender 的标头将映射到 META 键 HTTP_X_BENDER。

关键位是:Django 将“-”转换为下划线,并在其前面加上“HTTP_”。如果您在 调用 api 时已经添加了 HTTP_ 前缀,那么它可能会加倍。例如'HTTP_HTTP_SPECIES'

【讨论】:

  • 进行名称翻译的不是 Django,而是 WSGI 服务器。 WSGI 规范要求 WSGI 服务器填充 WSGI 环境字典,该字典在 Django 中成为 META,名称按照 CGI 规范规则进行翻译。所以最终这是由于 WSGI 的各个部分所基于的 CGI 规范所决定的。
  • Django 也确实得到了升级,但这应该不是问题,因为使用 django 服务器运行 API 时,一切正常。我知道上面提到的事情,但是它没有提到下划线是不可接受的,也没有提到这将是新版本的 django 中的内容。格雷厄姆,你可能正在那里做些什么,这可能是 wsgi 的罪魁祸首。
  • 您是否尝试过简单地打印出 request.META 映射及其所有键值?这会告诉你到底发生了什么。
  • 我有 Jon,但缺少包含下划线的参数。
猜你喜欢
  • 1970-01-01
  • 2017-09-08
  • 1970-01-01
  • 1970-01-01
  • 2019-03-13
  • 1970-01-01
  • 1970-01-01
  • 2018-06-27
  • 2017-05-29
相关资源
最近更新 更多