Python CGI:上传错误
我使用的是Python 3.4版本。
这是用Python写的服务器源代码。
import io
from socket import *
import threading
import cgi
serverPort = 8181
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(('', serverPort))
serverSocket.listen(5)
def serverHandle(connectionSocket, addr):
try:
message = connectionSocket.recv(1024)
if not message:
return
path = message.split()[1].decode('utf-8')
if path == '/':
connectionSocket.send(b'HTTP/1.1 200 OK\r\n')
connectionSocket.send(b'Content-type: text/html\r\n\r\n')
with open('upload.html', 'rb') as f:
connectionSocket.send(f.read())
elif path == '/upload':
header = message.split(b'\r\n\r\n')[0]
query = message.split(b'\r\n\r\n')[-1]
if not query:
return
fp = io.BytesIO(query)
form = cgi.FieldStorage(fp, environ={'REQUEST_METHOD':'POST', 'CONTENT_TYPE': 'multipart/form-data'})
f = open(form.filename, 'w')
f.write(form.file)
f.close()
connectionSocket.close()
except IOError:
connectionSocket.send('404 File Not Found\r\n\r\n'.encode('utf_8'))
connectionSocket.close()
while True:
connectionSocket, addr = serverSocket.accept();
threading._start_new_thread(serverHandle, (connectionSocket, addr))
serverSocket.close()
上传的HTML源代码在这里。
<HTML>
<BODY>
<FORM ENCTYPE="multipart/form-data" ACTION="http://127.0.0.1:8181/upload" METHOD=POST>
File to process: <INPUT NAME="file" TYPE="file">
<INPUT TYPE="submit" VALUE="Send File">
</FORM>
</BODY>
</HTML>
我尝试把文件上传到服务器,并把文件保存在一个目录里,但出现了这样的错误。
Unhandled exception in thread started by <function serverHandle at 0x000000000240CBF8>
Traceback (most recent call last):
File "C:\Users\Inwoo\Eclipse\workspace\WebServer\src\webserver1.py", line 36, in serverHandle
form = cgi.FieldStorage(fp, environ={'REQUEST_METHOD':'POST', 'CONTENT_TYPE': 'multipart/form-data'})
File "C:\Python34\lib\cgi.py", line 559, in __init__
self.read_multi(environ, keep_blank_values, strict_parsing)
File "C:\Python34\lib\cgi.py", line 681, in read_multi
raise ValueError('Invalid boundary in multipart form: %r' % (ib,))
ValueError: Invalid boundary in multipart form: b''
我不太明白这个问题是什么?
有时候消息的查询结果是空的!
所以我写了if not query: return
,这样写对吗?
我该如何接收上传的文件并把它们保存在服务器上呢?
1 个回答
1
你需要注意,不要把查询分割得太多,因为里面可能会有嵌入的换行符。这里可以用 str.partition()
来处理:
header, _, query = message.partition(b'\r\n\r\n')
你需要解析头部信息;Content-Type
头部包含了多部分的边界信息;FieldStorage
实例需要这个信息来判断字段的开始和结束。
import re
content_type = re.search(br'content-type:\s+(.*?)\r\n', header, flags=re.I).group(1)
form = cgi.FieldStorage(fp, environ={'REQUEST_METHOD':'POST', 'CONTENT_TYPE': content_type})
要记住,带文件上传的 HTTP 消息可能会包含超过 1024 字节的数据,而你只读取了这么一点点。仅仅是头部信息 就可能占据了大部分的消息;我的浏览器发送的头部信息就有 819 字节,并且这些信息会放在一个数据包里。你调用 connectionSocket.recv(1024)
时,得到的将仅仅是这些头部信息,你还需要继续读取更多的数据。