将二进制数据PUT到Django时的问题
我正在尝试用Django构建一个RESTful API来分享mp3文件——先说明一下:这只是个玩具应用,不会投入生产,所以不需要考虑扩展性,也希望不需要担心版权问题。
我现在的问题是,我有一个Django视图,想把它设置为处理HTTP PUT请求的端点。PUT请求的头部会包含一些元数据,而请求的主体则只包含二进制数据。
这是我想要访问的实际视图。请注意,日志显示控制流从未进入put()方法,我认为这是正确的,虽然不算特别稳健:
class UserSong(RESTView):
logging.debug('entering UserSong.put')
def put(self, request, username=''):
if request.META['Content-Type'] != 'octet/stream':
raise Http400()
title = request.META['X-BD-TITLE'] if 'X-BD-TITLE' in request.META else 'title unknown'
artist = request.META['X-BD-ARTIST'] if 'X-BD-ARTIST' in request.META else 'artist unknown'
album = request.META['X-BD-ALBUM'] if 'X-BD-ALBUM' in request.META else 'album unknown'
song_data = b6decode(request.raw_post_data)
song = Song(title=title, artist=artist, playcount=playcount, is_sample=is_sample, song_data=song_data, album=album)
song.save()
return HttpResponse('OK', 'text/plain' , 201)
def __call__(self, request, *args, **kwargs):
logging.basicConfig(filename=LOGFILE,level=logging.DEBUG)
try:
if request.method == 'DELETE':
return self.delete(request, *args, **kwargs)
elif request.method == 'GET':
return self.get(request, *args, **kwargs)
elif request.method == 'POST':
return self.post(request, *args, **kwargs)
elif request.method == 'PUT':
return self.put(request, *args, **kwargs)
except:
raise Http404()
在测试这个的时候,我用Django的单元测试框架让测试通过了,但我不太相信这能准确模拟真实情况。所以,我打开了httplib,自己构造了一个PUT请求。这是我交互执行的代码:
>>>method = 'PUT'
>>>url = 'accounts/test/songs/'
>>>f = open('/Users/bendean/Documents/BEARBOT.mp3')
>>>data = f.read()
>>>body = data
>>>headers = {'X-BD-ARTIST' : 'BEARBOT' , 'X-BD-ALBUM':'','X-BD-TITLE':'LightningSPRKS'}
>>>headers['CONTENT-TYPE'] = 'octet/stream'
>>>import httplib
>>>c = httplib.HTTPConnection('localhost:8000')
>>>c.request(method, url, body, headers)
我得到的响应并不好看
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py", line 880, in request
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py", line 914, in _send_request
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py", line 719, in send
File "<string>", line 1, in sendall
error: [Errno 54] Connection reset by peer
不过有时候我会得到
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py", line 880, in request
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py", line 914, in _send_request
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py", line 719, in send
File "<string>", line 1, in sendall
error: [Errno 32] Broken pipe
我对我的URL是有效的很有信心(GET请求处理得很好,谢谢)。日志显示请求实际上并没有到达处理代码。
在网上搜索后,我发现一些问题追踪器建议,问题可能出在httplib处理上传大文件时的错误(这个文件是3.7MB)。
所以,我不怕承认我在这方面有点无从下手——我该如何确定是什么导致了错误?我的请求格式正确吗(顺便说一下,我也尝试过对主体进行b64编码,结果是一样的)?从更大的角度来看,我这样做(为了测试,而不是在实际应用中)合理吗?这和开发服务器上的可配置设置有关吗?如果我把这个放到Apache上,这些问题会消失吗?非常感谢你的帮助。
1 个回答
0
看起来问题出在开发服务器处理大请求时。把程序部署到使用mod_wsgi的Apache服务器上后,这个问题就解决了。不过我对RESTful文件上传还有很多疑问...