踏到這個雷兩次了, 記錄一下。
在使用 runserver 開發程式時, runserver 會特別處理 ADMIN_MEDIA_PREFIX, 先處理 prefix 為 ADMIN_MEDIA_PREFIX 的路徑, 再將其它情況交回給原本 urls.py 裡定義的 handler。
這導致當自己的靜態檔案放在 media/ 下, 又忘了改 ADMIN_MEDIA_PREFIX 時 ( settings.py 預設為 media/), 會讀不到自己 media/ 下的檔案, 而出現 "Page not found: ..." 的錯誤訊息。
從以下兩個現象, 推測中間有人先處理掉 request:
- browser 有送出 request 但得到 404
- runserver 的 console 沒輸出訊息表示有收到 request 並回覆 404
所以推測有人從中做梗!!
解法很簡單, 就是將 ADMIN_MEDIA_PREFIX 隨便設一個其它名稱, 像是 "admin_media"。之前有人發 issue 請 Django 改掉 django-admin.py 的值, 不過下場是 wontfix。
相關的程式從 core/management/commands/runserver.py 找到 core/servers/basehttp.py, 然後看 AdminMediaHandler.call 的部份。
這段先看是否符合 ADMIN_MEDIA_PREFIX , 不是的話就由原本使用者寫的方式處理:
# Ignore requests that aren't under ADMIN_MEDIA_PREFIX. Also ignore # all requests if ADMIN_MEDIA_PREFIX isn't a relative URL. 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_PREFIX 的特殊處理, 也只是看檔案、讀檔案而已:
# Find the admin file and serve it up, if it exists and is readable. try: file_path = self.file_path(environ['PATH_INFO']) except ValueError: # Resulting file path was not valid. status = '404 NOT FOUND' headers = {'Content-type': 'text/plain'} output = ['Page not found: %s' % environ['PATH_INFO']] start_response(status, headers.items()) return output if not os.path.exists(file_path): status = '404 NOT FOUND' headers = {'Content-type': 'text/plain'} output = ['Page not found: %s' % environ['PATH_INFO']] else: try: fp = open(file_path, 'rb') except IOError: status = '401 UNAUTHORIZED' headers = {'Content-type': 'text/plain'} output = ['Permission denied: %s' % environ['PATH_INFO']] ...
沒有留言:
張貼留言