提前为冗长的篇幅道歉,感谢您的耐心。我有一个古老的生产服务器,没有人知道它是如何构建的。它使用 apache+mod_wsgi 运行 Cherry Py python 应用程序来提供图像。我正在重新创建它以记录它并开始升级。我遇到了一个问题,没有文件扩展名的图像(可以是 PNG 或 JPEG)通过:
Content-Type: "text/html;charset=utf-8"
生产服务器当前正确返回:
Content-Type: "image/jpeg"
有关我正在其中重新创建服务器的环境的信息:
Amazon Linux AMI release 2017.03 (basically CentOS 6 it feels like)
Apache/2.2.31
mod_wsgi-3.4
CherryPy 3.2.0
生产环境安装了相同的软件包,只是它在实际的 Centos6 上运行,并且 Apache 版本是 2.2.17。
文件和相关片段:
httpd配置文件
#/etc/httpd/conf/httpd.conf
LoadModule mime_magic_module modules/mod_mime_magic.so
LoadModule mime_module modules/mod_mime.so
TypesConfig /etc/mime.types
<IfModule mod_mime_magic.c>
# MIMEMagicFile /usr/share/magic.mime
MIMEMagicFile conf/magic
</IfModule>
Include conf.sites/*.conf
# There really are no other directives or AddType calls that are relevant
# that I can see, just standard language and icon declarations
# if I should be more verbose here just let me know.
魔法
# /etc/httpd/conf/magic
# JPEG images
0 beshort 0xffd8 image/jpeg
mime 类型
# /etc/mime.types
image/jpeg jpeg jpg jpe jfif
站点配置文件
# /etc/httpd/conf.sites/site.conf
<VirtualHost *:80>
ServerName pic.project.com
DocumentRoot "/srv/pic_project/html"
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} Apache\sHttpClient [NC]
RewriteRule . - [F,L]
<Directory /srv/pic_project/html>
Order allow,deny
Allow from all
</Directory>
WSGIScriptAlias / /srv/pic_project/src/project.py
<Directory /srv/pic_project/src>
Order allow,deny
Allow from all
</Directory>
ErrorLog logs/pic-error_log
CustomLog logs/pic-access_log combined
</VirtualHost>
cherry py用于提供照片的文件:
# /srv/pic_project/src/project.py
cherrypy.response.headers['Content-Type'] = cfile.mimetype
cherrypy.response.headers['Cherry-Py-Content-Type'] = cfile.mimetype
cherrypy.response.headers['Content-Disposition'] = 'inline; filename="12345.jpg"'
# I set two headers for debugging. Cherry-Py-Content-Type is always right
# "image/jpeg" or "image/png". "Content-Type" is always "text/html" once
# going through apache / mod_wsgi. Don't worry about "cfile", just know
# the mimetype attribute is always correct.
请求的url类似如下:
http://pic.project.com/pics/pic_type/owner_id/12345/
补充笔记:
- 生产服务器 + 我的娱乐具有客户端代码的精确副本,因此问题不太可能出在 cherry py / python 代码中。
- httpd.conf、magic、mime.types、虚拟主机文件是生产服务器上的精确副本,因此不太可能是问题所在。
- 当访问该 URL 时,浏览器中显示的文本以 JFIF 开头,表示它确实找到了该图像。
我目前所做的:
- 在声明 Content-Type 响应标头之后立即设置自定义响应标头,以确认应用程序设置了正确的值。
- 对文件位置/权限进行了三重检查,然后让另外两位同事也检查。
- 在 /etc/httpd/conf/httpd.conf 的底部添加了一行以强制 Content-Type 标头:
Header set Content-Type "image/jpeg"
,然后逐步将其移动到文件顶部以查看是否最终像应用程序标头一样被覆盖,但只要该行位于 conf 文件中的任何位置,它就会工作/不会被覆盖。(请记住它可能是 PNG 或 JPEG,因此静态设置它是行不通的)。 - 扫描生产 + 娱乐以查找任何可能产生影响的 .htaccess 文件,我没有找到任何文件,运行:
sudo find / -type f -name .htaccess
什么也没找到。 - 确认所有生产 Apache 模块均已在重新安装
- 确认错误日志中没有消息,访问日志按预期显示请求,系统日志中没有任何内容。
根据我读过的类似问题,例如:
其中一条评论说,为了使 mime_magic 正常工作,mod_mime 必须找不到任何匹配项,但由于没有扩展名,它会找到一堆匹配项,因此 mime_magic 甚至从未进入游戏。这是准确的吗?如果是这样,我可以强制它始终使用 magic 而不使用扩展名吗?否则,还有哪些其他方法可以根据内容正确设置没有扩展名的文件的 Content-Type?
另一个人会说,您可以使用ForceType
指令来匹配特定目录中的文件模式。问题是文件名只是数字,没有按类型分隔,所以 /thing/12345 和 /thing/12346 一个可能是 PNG,另一个可能是 JPEG,所以我不能强制使用模式,我需要根据文件内容确定类型。
另一个是在应用程序中声明了错误的 Content-Type,但我已经确认事实并非如此。
我已经阅读了几十个其他答案并尝试了多种解决方法,但我认为我只是忽略了一些简单的东西。
如果您读到这里,感谢您的时间!欢迎提出任何建议。将根据要求添加任何缺失/有用的调试信息!
答案1
我的具体问题的答案是有人在生产机器上手动编辑了生成的配置文件。由于生成的配置未提交到版本控制,而是将环境模板复制为基于环境的配置,因此模板也未更新。基本上,如果我们在生产机器上运行构建,它也会出现此问题。我遗漏的 Cherry Py 配置选项是:
tools.encode.add_charset = False
如果没有这个,cherry py 就会覆盖应用程序中设置的 Content-Type 标头。结果发现与 Apache / mod_mime / magic / modwsgi 无关。这都是 Cherry Py 配置问题。