<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        Flask/MongoDB搭建簡易圖片服務器

        來源:懂視網 責編:小采 時間:2020-11-09 13:18:46
        文檔

        Flask/MongoDB搭建簡易圖片服務器

        Flask/MongoDB搭建簡易圖片服務器:前期準備 通過 pip 或 easy_install 安裝了 pymongo 之后, 就能通過 Python 調教 mongodb 了. 接著安裝個 flask 用來當 web 服務器. 當然 mongo 也是得安裝的. 對于 Ubuntu 用戶, 特別是使用 Server 12.04 的同學, 安裝最新版要略費些周折
        推薦度:
        導讀Flask/MongoDB搭建簡易圖片服務器:前期準備 通過 pip 或 easy_install 安裝了 pymongo 之后, 就能通過 Python 調教 mongodb 了. 接著安裝個 flask 用來當 web 服務器. 當然 mongo 也是得安裝的. 對于 Ubuntu 用戶, 特別是使用 Server 12.04 的同學, 安裝最新版要略費些周折

        前期準備 通過 pip 或 easy_install 安裝了 pymongo 之后, 就能通過 Python 調教 mongodb 了. 接著安裝個 flask 用來當 web 服務器. 當然 mongo 也是得安裝的. 對于 Ubuntu 用戶, 特別是使用 Server 12.04 的同學, 安裝最新版要略費些周折, 具體說是 sudoapt

        前期準備

        通過 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

        或 (更適合 Windows 用戶)

        easy_install Pillow

        正片

        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 '''




        '''

        if __name__ == '__main__':
        app.run(port=7777)

      1. 注: 在 upload 函數中, 使用 flask.request.files[KEY] 獲取上傳文件對象, KEY 為頁面 form 中 input 的 name 值
      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 編碼.

        提供文件訪問

        給定存進數據庫的文件的 ID (作為 URI 的一部分), 返回給瀏覽器其文件內容, 如下

        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/')
        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 函數會跳轉到對應的文件瀏覽頁. 這樣一來, 文本文件內容就可以正常預覽了, 如果不是那么挑剔換行符跟連續空格都被瀏覽器吃掉的話.

        當找不到文件時

        有兩種情況, 其一, 數據庫 ID 格式就不對, 這時 pymongo 會拋異常 bson.errors.InvalidId; 其二, 找不到對象 (!), 這時 pymongo 會返回 None.
        簡單起見就這樣處理了

        @app.route('/f/')
        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)

        正確的 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/')
        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() 清掉原來的數據.

        根據上傳時間給出 NOT MODIFIED

        利用 HTTP 304 NOT MODIFIED 可以盡可能壓榨與利用瀏覽器緩存和節省帶寬. 這需要三個操作
      3. 記錄文件最后上傳的時間
      4. 當瀏覽器請求這個文件時, 向請求頭里塞一個時間戳字符串
      5. 當瀏覽器請求文件時, 從請求頭中嘗試獲取這個時間戳, 如果與文件的時間戳一致, 就直接 304
      6. 體現為代碼是

        import datetime

        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,
        time=datetime.datetime.utcnow(),
        )
        db.files.save(c)
        return c['_id']

        @app.route('/f/')
        def serve_file(fid):
        try:
        f = db.files.find_one(bson.objectid.ObjectId(fid))
        if f is None:
        raise bson.errors.InvalidId()
        if flask.request.headers.get('If-Modified-Since') == f['time'].ctime():
        return flask.Response(status=304)
        resp = flask.Response(f['content'], mimetype='image/' + f['mime'])
        resp.headers['Last-Modified'] = f['time'].ctime()
        return resp
        except bson.errors.InvalidId:
        flask.abort(404)

        然后, 得弄個腳本把數據庫里面已經有的圖片給加上時間戳.
        順帶吐個槽, 其實 NoSQL DB 在這種環境下根本體現不出任何優勢, 用起來跟 RDB 幾乎沒兩樣.

        利用 SHA-1 排重

        與冰箱里的可樂不同, 大部分情況下你肯定不希望數據庫里面出現一大波完全一樣的圖片. 圖片, 連同其 EXIFF 之類的數據信息, 在數據庫中應該是惟一的, 這時使用略強一點的散列技術來檢測是再合適不過了.
        達到這個目的最簡單的就是建立一個 SHA-1 惟一索引, 這樣數據庫就會阻止相同的東西被放進去.
        在 MongoDB 中表中建立惟一索引, 執行 (Mongo 控制臺中)

        db.files.ensureIndex({sha1: 1}, {unique: true})

        如果你的庫中有多條記錄的話, MongoDB 會給報個錯. 這看起來很和諧無害的索引操作被告知數據庫中有重復的取值 null (實際上目前數據庫里已有的條目根本沒有這個屬性). 與一般的 RDB 不同的是, MongoDB 規定 null, 或不存在的屬性值也是一種相同的屬性值, 所以這些幽靈屬性會導致惟一索引無法建立.
        解決方案有三個
      7. 刪掉現在所有的數據 (一定是測試數據庫才用這種不負責任的方式吧!)
      8. 建立一個 sparse 索引, 這個索引不要求幽靈屬性惟一, 不過出現多個 null 值還是會判定重復 (不管現有數據的話可以這么搞)
      9. 寫個腳本跑一次數據庫, 把所有已經存入的數據翻出來, 重新計算 SHA-1, 再存進去
      10. 具體做法隨意. 假定現在這個問題已經搞定了, 索引也弄好了, 那么剩是 Python 代碼的事情了.

        import hashlib

        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)

        sha1 = hashlib.sha1(content.getvalue()).hexdigest()
        c = dict(
        content=bson.binary.Binary(content.getvalue()),
        mime=mime,
        time=datetime.datetime.utcnow(),
        sha1=sha1,
        )
        try:
        db.files.save(c)
        except pymongo.errors.DuplicateKeyError:
        pass
        return c['_id']

        在上傳文件這一環就沒問題了. 不過, 按照上面這個邏輯, 如果上傳了一個已經存在的文件, 返回 c['_id'] 將會是一個不存在的數據 ID. 修正這個問題, 最好是返回 sha1, 另外, 在訪問文件時, 相應地修改為用文件 SHA-1 訪問, 而不是用 ID.
        最后修改的結果及本篇完整源代碼如下

        import hashlib
        import datetime
        import flask
        import pymongo
        import bson.binary
        import bson.objectid
        import bson.errors
        from cStringIO import StringIO
        from PIL import Image

        app = flask.Flask(__name__)
        app.debug = True
        db = pymongo.MongoClient('localhost', 27017).test
        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)

        sha1 = hashlib.sha1(content.getvalue()).hexdigest()
        c = dict(
        content=bson.binary.Binary(content.getvalue()),
        mime=mime,
        time=datetime.datetime.utcnow(),
        sha1=sha1,
        )
        try:
        db.files.save(c)
        except pymongo.errors.DuplicateKeyError:
        pass
        return sha1

        @app.route('/f/')
        def serve_file(sha1):
        try:
        f = db.files.find_one({'sha1': sha1})
        if f is None:
        raise bson.errors.InvalidId()
        if flask.request.headers.get('If-Modified-Since') == f['time'].ctime():
        return flask.Response(status=304)
        resp = flask.Response(f['content'], mimetype='image/' + f['mime'])
        resp.headers['Last-Modified'] = f['time'].ctime()
        return resp
        except bson.errors.InvalidId:
        flask.abort(404)

        @app.route('/upload', methods=['POST'])
        def upload():
        f = flask.request.files['uploaded_file']
        sha1 = save_file(f)
        return flask.redirect('/f/' + str(sha1))

        @app.route('/')
        def index():
        return '''




        '''

        if __name__ == '__main__':
        app.run(port=7777)

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        Flask/MongoDB搭建簡易圖片服務器

        Flask/MongoDB搭建簡易圖片服務器:前期準備 通過 pip 或 easy_install 安裝了 pymongo 之后, 就能通過 Python 調教 mongodb 了. 接著安裝個 flask 用來當 web 服務器. 當然 mongo 也是得安裝的. 對于 Ubuntu 用戶, 特別是使用 Server 12.04 的同學, 安裝最新版要略費些周折
        推薦度:
        標簽: 圖片 簡易 服務器
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 中文字幕亚洲综合久久2| 国产亚洲精品va在线| 2017亚洲男人天堂一| 亚洲网站免费观看| 亚洲黄色在线视频| 最近2019中文字幕免费直播 | 十八禁无码免费网站| 亚洲国产婷婷六月丁香| 国产在线国偷精品免费看| 国产成人精品曰本亚洲79ren| 日韩免费高清一级毛片| 亚洲精品WWW久久久久久| 国产精品黄页免费高清在线观看| 亚洲人成色77777在线观看大| 精品久久久久久无码免费| 亚洲日韩av无码| 91精品成人免费国产片| 亚洲男人天堂2018av| 日韩一区二区在线免费观看 | a毛片在线免费观看| 亚洲一区免费观看| 久久受www免费人成_看片中文| 亚洲熟女综合色一区二区三区 | 中国人xxxxx69免费视频| 国产成人亚洲综合网站不卡| 国产成人在线观看免费网站| 久久性生大片免费观看性| 亚洲精品美女久久久久9999| 毛片基地免费视频a| 一级毛片a女人刺激视频免费| 亚洲国产精品va在线播放| 成人福利免费视频| 美女黄频视频大全免费的| 亚洲精品无码久久千人斩| 91香蕉国产线在线观看免费| 亚洲AV色无码乱码在线观看| 国产亚洲精品成人AA片新蒲金| 成人免费视频69| WWW国产成人免费观看视频| 亚洲精品中文字幕麻豆| 内射无码专区久久亚洲|