调用send_file()时返回文本文档而不是图像

时间:2015-11-20 03:27:53

标签: python web flask

我想从服务器端向客户端发送图像文件。我正在使用flask框架。

但问题是每当我调用send_file()的路由时,响应返回就是文件。当我单击此文件gedit时,该文件中没有任何内容打开它。这意味着它必须是文本文件。

我提到了send_file()的烧瓶文档。

以下是我在代码中所做的事情:

@app.route('/try')
def trial():
    todown = 'https://igcdn-photos-e-a.akamaihd.net//hphotos-ak-xaf1//t51.2885-15//e35//12093691_1082288621781484_1524190206_n.jpg'  
    resp = requests.get(todown)
    return send_file(resp,mimetype="image/jpeg",attachment_filename="img.jpg",as_attachment=True)

每当我加载localhost:5000/try时,都会下载文件,但不会下载我要下载的图像文件。

我在终端中遇到的错误是AttributeError: 'Response' object has no attribute 'read' error

一定是什么问题。上面的代码片段中是否缺少任何内容?

1 个答案:

答案 0 :(得分:11)

  1. resprequests.models.Response对象,不是字符串也不是字节:

    >>> import requests
    >>> todown = 'https://igcdn-photos-e-a.akamaihd.net//hphotos-ak-xaf1//t51.2885-15//e35//12093691_1082288621781484_1524190206_n.jpg'
    >>> resp = requests.get(todown)
    >>> resp
    <Response [200]>
    >>> type(resp)
    <class 'requests.models.Response'>
    
  2. Flask.send_file() 发送文件

  3. 首先,你需要使用resp.content来获取对象的内容,它将返回bytes对象(顺便说一下,resp.text返回字符串对象。 如果您正在下载图片,视频或其他非文字内容,请务必使用.content

    >>> import requests
    >>> todown = 'https://igcdn-photos-e-a.akamaihd.net//hphotos-ak-xaf1//t51.2885-15//e35//12093691_1082288621781484_1524190206_n.jpg'
    >>> resp = requests.get(todown)
    >>> type(resp.content)
    <class 'bytes'>
    

    请查看the document了解详情。

    然后,因为Flask.send_file() 发送文件,所以您需要在发送之前将图像写入文件。

    但是,既然你不需要在服务器上使用这个图像,我建议在这种情况下使用io.BytesIO,然后在发送之后不需要删除该图像。请注意,如果您要发送文本文件,请使用io.StringIO

    例如:

    import requests
    from io import BytesIO
    from flask import Flask, send_file
    
    app = Flask(__name__)
    
    @app.route('/')
    def tria():
        todown = 'https://igcdn-photos-e-a.akamaihd.net//hphotos-ak-xaf1//t51.2885-15//e35//12093691_1082288621781484_1524190206_n.jpg'
        resp = requests.get(todown)
        return send_file(BytesIO(resp.content), mimetype="image/jpeg", attachment_filename="img2.jpg", as_attachment=True)
    
    app.run(port=80, debug=True)
    

    但是,如果您想将图像写入文件然后发送,请确保您也可以这样做。我们可以使用tempfile.NamedTemporaryFile()创建 tempfile ,而不是仅创建一个文件以避免重写您的重要文件。

    来自文件:

      

    此函数与TemporaryFile()完全相同,但保证文件在文件系统中具有可见名称(在Unix上,目录条目未取消链接)。

         

    可以从文件对象的name属性中检索该名称。名称是否可以用于第二次打开文件,而命名的临时文件仍然是打开的,因此不同平台(它可以在Unix上使用;它不能在Windows NT或更高版本上使用)。如果delete为true(默认值),则文件一关闭就会被删除。

         

    返回的对象始终是类文件对象,其file属性是底层的真实文件对象。这个类文件对象可以在with语句中使用,就像普通文件一样。

    例如:

    import tempfile
    import requests
    from flask import Flask, send_file
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def tria():
        todown = 'https://igcdn-photos-e-a.akamaihd.net//hphotos-ak-xaf1//t51.2885-15//e35//12093691_1082288621781484_1524190206_n.jpg'
    
        resp = requests.get(todown)
    
        with tempfile.NamedTemporaryFile() as f:  
            # create a file-like object use `NamedTemporaryFile()` and `with` 
            # as the basic usage which said in the document     
    
            f.write(resp.content)
            # write the content of the image into it
    
            return send_file(f.name, mimetype="image/jpeg",
                             attachment_filename="img2.jpg", as_attachment=True)                             
            # `f.name` is the temp file's filename
    
    app.run(port=80, debug=True)