设为首页 收藏本站
查看: 2924|回复: 0

[经验分享] Python中使用Flask、MongoDB搭建简易图片服务器

[复制链接]

尚未签到

发表于 2017-12-16 10:42:16 | 显示全部楼层 |阅读模式
  1、前期准备
  通过 pip 或 easy_install 安装了 pymongo 之后, 就能通过 Python 调教 mongodb 了.
  接着安装个 flask 用来当 web 服务器.
  当然 mongo 也是得安装的. 对于 Ubuntu 用户, 特别是使用 Server 12.04 的同学, 安装最新版要略费些周折, 具体说是
  

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10  
echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list
  
sudo apt-get update
  
sudo apt-get install mongodb-10gen
  

  

  如果你跟我一样觉得让通过上传文件名的后缀判别用户上传的什么文件完全是捏着山药当小黄瓜一样欺骗自己, 那么最好还准备个 Pillow 库
  

pip install Pillow  

  2、正片
  2.1 Flask 文件上传
  Flask 官网上那个例子居然分了两截让人无从吐槽. 这里先弄个最简单的, 无论什么文件都先弄上来
  

import flask  
app = flask.Flask(__name__)
  
app.debug = True
  
@app.route('/upload', methods=['POST'])
  
def upload():
  f = flask.request.files['uploaded_file']
  print f.read()
  return flask.redirect('/')
  
@app.route('/')
  
def index():
  return '''
  <!doctype html>
  <html>
  <body>
  <form action='/upload' method='post' enctype='multipart/form-data'>
  <input type='file' name='uploaded_file'>
  <input type='submit' value='Upload'>
  </form>
  '''
  
if __name__ == '__main__':
  app.run(port=7777)
  

  

  注: 在 upload 函数中, 使用 flask.request.files[KEY] 获取上传文件对象, KEY 为页面 form 中 input 的 name 值
  因为是在后台输出内容, 所以测试最好拿纯文本文件来测.
  2.2 保存到 mongodb
  如果不那么讲究的话, 最快速基本的存储方案里只需要
  

import pymongo  
import bson.binary
  
from cStringIO import StringIO
  
app = flask.Flask(__name__)
  
app.debug = True
  
db = pymongo.MongoClient('localhost', 27017).test
  
def save_file(f):
  content = StringIO(f.read())
  db.files.save(dict(
  content= bson.binary.Binary(content.getvalue()),
  ))
  
@app.route('/upload', methods=['POST'])
  
def upload():
  f = flask.request.files['uploaded_file']
  save_file(f)
  return flask.redirect('/')
  

  

  

  把内容塞进一个  bson.binary.Binary  对象, 再把它扔进 mongodb 就可以了.
  现在试试再上传个什么文件, 在 mongo shell 中通过  db.files.find() 就能看到了.
  不过 content  这个域几乎肉眼无法分辨出什么东西, 即使是纯文本文件, mongo 也会显示为 Base64 编码.
  2.3 提供文件访问

  给定存进数据库的文件的>  

def save_file(f):  content = StringIO(f.read())
  c = dict(content=bson.binary.Binary(content.getvalue()))
  db.files.save(c)
  return c['_id']
  
@app.route('/f/<fid>')
  
def serve_file(fid):
  f = db.files.find_one(bson.objectid.ObjectId(fid))
  return f['content']
  
@app.route('/upload', methods=['POST'])
  
def upload():
  f = flask.request.files['uploaded_file']
  fid = save_file(f)
  return flask.redirect( '/f/' + str(fid))
  

  

  

  上传文件之后,  upload  函数会跳转到对应的文件浏览页. 这样一来, 文本文件内容就可以正常预览了, 如果不是那么挑剔换行符跟连续空格都被浏览器吃掉的话.
  2.4 当找不到文件时

  有两种情况, 其一, 数据库>  简单起见就这样处理了
  

@app.route('/f/<fid>')  
def serve_file(fid):
  import bson.errors
  try:
  f = db.files.find_one(bson.objectid.ObjectId(fid))
  if f is None:
  raise bson.errors.InvalidId()
  return f['content']
  except bson.errors.InvalidId:
  flask.abort(404)
  

  

  

  2.5 正确的 MIME
  从现在开始要对上传的文件严格把关了, 文本文件, 狗与剪刀等皆不能上传.
  判断图片文件之前说了我们动真格用 Pillow
  

from PIL import Image  
allow_formats = set(['jpeg', 'png', 'gif'])
  
def save_file(f):
  content = StringIO(f.read())
  try:
  mime = Image.open(content).format.lower()
  if mime not in allow_formats:
  raise IOError()
  except IOError:
  flask.abort(400)
  c = dict(content=bson.binary.Binary(content.getvalue()))
  db.files.save(c)
  return c['_id']
  

  

  

  然后试试上传文本文件肯定虚, 传图片文件才能正常进行. 不对, 也不正常, 因为传完跳转之后, 服务器并没有给出正确的 mimetype, 所以仍然以预览文本的方式预览了一坨二进制乱码.
  要解决这个问题, 得把 MIME 一并存到数据库里面去; 并且, 在给出文件时也正确地传输 mimetype
  

def save_file(f):  content = StringIO(f.read())
  try:
  mime = Image.open(content).format.lower()
  if mime not in allow_formats:
  raise IOError()
  except IOError:
  flask.abort(400)
  c = dict(content=bson.binary.Binary(content.getvalue()), mime=mime)
  db.files.save(c)
  return c['_id']
  
@app.route('/f/<fid>')
  
def serve_file(fid):
  try:
  f = db.files.find_one(bson.objectid.ObjectId(fid))
  if f is None:
  raise bson.errors.InvalidId()
  return flask.Response(f['content'], mimetype='image/' + f['mime'])
  except bson.errors.InvalidId:
  flask.abort(404)
  

  

  

  当然这样的话原来存进去的东西可没有 mime 这个属性, 所以最好先去 mongo shell 用  db.files.drop()  清掉原来的数据.

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-424650-1-1.html 上篇帖子: CI框架使用扩展mongodb和memcache 下篇帖子: mongodb副本集优先级设置
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表