IUSR's Ughten of Silent Requiem

To whom it may resurrect
zh en ja

解决django runserver发送静态文件的一个配置问题

2011-01-06 技术文章

首先,不管常识也好,django自己的文档 也罢,用应用服务器发送静态资源文件一直就不是什么好办法,尤其用python、java这种东西做的应用服务器,几乎没什么可能达到apache、lighttpdcherokeenginx 之流的性能——当然有人说nginx是web应用平台,换而言之,应用服务器,这个我也没话说。

有关配置django通过runserver方式启动的开发测试用服务器处理用来发送静态文件的文档在:http://docs.djangoproject.com/en/1.2/howto/static-files/ ,也是警告了无数次这样做不好,只限于开发目的。

近来和几个同学做个练手的小东西,基本上就我还算知道一些web方面的事儿,大伙都是传统软件开发行业出身,nginx这种看起来很geeky的东西,八成下意识都觉得离远点儿好(这也是当初为啥我看了一阵子cherokee ,毕竟管理UI太Q太省心了…),所以和哥儿几个白话了会儿选型,就有人问,诶,能让django直接管HTTP服务嘛?想想也可以理解,nginx那东西,win下还不知道啥德行了,反正我没碰过,出什么问题真耽误人家时间啊。遂折腾了一下,照文档配的,也很简单,可最后静态资源怎么都是找不到,怎么看配置都没问题的啊…

后来问题解决了,其实可能也就是个比较不常见的配置问题,原因是我把admin和site的media目录配成同一个了…当初就是觉得一是省事,二是看了看admin里的js和css,有一些东西很有重用的价值。没想到给后来埋下这么个麻烦。

怎么改配置文件都没法解决问题,直接看代码吧。

调用流程是:

    manage.py
  -> django.core.management.execute_manager()
  -> django.core.management.ManagementUtility.execute()
  -> django.core.management.commands.runserver.Command.handle()
  -> django.core.servers.basehttp.run()
  -> django.core.servers.basehttp.WSGIRequestHandler.handle()
  -> django.core.servers.basehttp.ServerHandler.run()
  -> django.core.servers.basehttp.AdminMediaHandler.()

让我最开始很迷惑的就是runserver.Command里面直接诡异地传了AdminMediaHandler去后续处理请求,刚开始看代码的时候总觉得是不是哪里看错了,让个这么霸道的名字唬住了。后来一通traceback.print_stack()才敢确信,配好的django.views.static.serve()根本就没调到。

因为,AdminMediaHandler()中有这么一段判断:

  if self.media_url.startswith('http://') or self.media_url.startswith('https://') or not environ['PATH\_INFO'].startswith(self.media_url):
  return self.application(environ, start\_response)

因为配置里的ADMIN_MEDIA_PREFIXMEDIA_URL都是/media/,就会导致这个条件判断为False无法进到application(),which会辗转进入后面的django.views.static.serve(),而是在admin应用的media里寻找文件,最后因为找不到返回HTTP 404。

解决方法嘛,也没啥太好的方法,不值得因为这么个破事儿去hack配置文件,把开发环境和部署环境搞的差异很大,所以就把admin用到的静态文件挪了挪窝 :D

至于为啥要打开admin嘛…我就是觉得admin挺好玩的…

comments powered by Disqus