Tornado的每个请求(Handler)实例均有request对象,当然可以试着把此对象打印出来。
在request中包涵了重要的属性,如files,arguments,path,headers。
其中:
访问的网址路径,不过是?前的,也就是忽略后面的参数
上传的文件信息,是一个上传的文件字典,字典的key是input的name属性,值对应了一个文件列表
所以我们在Handler中要处理上传的文件,必然是对request.files这个列表进行操作。
前端HTML没啥好说的
<!DOCTYPE html><head><title></title></head><body><form action="/upload" enctype="mutilpart/form-data" method="post"><input type="file" name="mypicture" /><button type="submit">Upload</button></form></body></html>
此后在处理上传的handler中,其request.files中会记录了你上传的信息,格式如下:
{"mypicture":[{'filename':'', 'content_type':'', 'body':''}]}
接下来思路就是先选择上传的文件,然后在进行一些格式、大小等判断,再进行存储处理。
Tornado上传图片
01 |
# 假设将/upload交给UploadHandler处理的话 |
10 |
class UploadHandler(tornado.web.RequestHandler): |
12 |
if self.request.files == {} or 'mypicture' not in self.request.files: |
13 |
""" 看是否有文件且name为picture,跟HTML代码对应 """ |
14 |
self.write('<script>alert("请选择图片")</script>') |
17 |
# 常用的图片格式有:image/jpeg,image/bmp,image/pjpeg,image/gif,image/x-png,image/png |
18 |
image_type_list = ['image/gif', 'image/jpeg', |
19 |
'image/pjpeg', 'image/bmp', 'image/png', 'image/x-png'] |
20 |
send_file = self.request.files['mypicture'][0] |
21 |
if send_file['content_type'] not in image_type_list: |
22 |
self.write('<script>alert("仅支持jpg,jpeg,bmp,gif,png格式的图片!")</script>') |
24 |
# 上述判断含有很大的上传漏洞,可以通过PIL来避免这些。 |
25 |
# 限制上传文件的大小,通过len获取字节数 |
26 |
if len(send_file['body']) > 4 * 1024 * 1024: |
27 |
self.write('<script>alert("请上传4M以下的图片");</script>') |
30 |
# 存储也就是将send_file['body']内容进行存储,type(send_file['body'])为str |
31 |
# 先将文件写入临时文件,然后再用PIL对这个临时文件进行处理。 |
32 |
tmp_file = tempfile.NamedTemporaryFile(delete=True) #创建临时文件,当文件关闭时自动删除 |
33 |
tmp_file.write(send_file['body']) #写入临时文件 |
34 |
tmp_file.seek(0) #将文件指针指向文件头部,因为上面的操作将指针指向了尾部。 |
36 |
#此时用PIL再处理进行存储,PIL打开不是图片的文件会出现IOERROR错误,这就可以识别后缀名虽然是图片格式,但内容并非是图片。 |
38 |
image_one = Image.open( tmp_file.name ) |
39 |
except IOError, error: |
40 |
logging.info(error) # 进行日志记录,因为这些操作大多数是破坏者的做法。 |
41 |
logging.info('+'*30 + 'n') |
42 |
logging.info(self.request.headers) |
44 |
self.write('<script>alert("图片不合法!")</script>') |
48 |
if image_one.size[0] < 250 or image_one.size[1] < 250 or |
49 |
image_one.size[0] > 2000 or image_one.size[1] > 2000: |
51 |
self.write('<script>alert("图片长宽在250px~2000px之间!")</script>') |
57 |
# 获取文件格式,用PIL获得的format不一定正确,所以用原文件名获得 |
58 |
image_path = "./static/picture/" |
59 |
image_format = send_file['filename'].split('.').pop().lower() |
60 |
tmp_name = image_path + str(int(time.time())) + image_format |
61 |
image_one.save(tmp_name) |
65 |
self.write('<script>alert("文件上传成功,路径为:" + image_path[1:])</script>') |
68 |
#以上就是简单的图片上传处理,一个应用应该有很复杂的图片处理技术,你可以用PIL对图片进行更多的处理来达到目标。 |
上述代码是处理上***个图片文件的处理程序。
当然这样的方法也并不好,每次判断都需要在信息传输至服务器端才可以,浪费了带宽,降低了效率。而且对于上传的文件过大,tornado本身就会出现错误。可以采用nginx的图片模块对图片文件的上传进行控制,可以做到在刚传输的时候就知道文件大小和文件类型,这些都是HTTP的规范