简体   繁体   English

从 Python 中的 API 服务器重定向下载文件

[英]Redirect a download file from API server in Python

I have 2 server: one backend for API and another one as web-frontend.我有 2 台服务器:一台用于 API 的后端,另一台作为 Web 前端。 The backend is working and provides files:后端正在工作并提供文件:

#API class for the route in Flask
class DownloadDocument(Resource):

    def get(self):

        # accept the filename which must be downloaded in HTTP request.
        # That file is surely present in the directory

        filename = request.headers.get('x-filename')      
       
        return send_from_directory(app.config['UPLOAD_FOLDER'], filename, as_attachment=True)

The web-frontend is currently getting the file in this way:网络前端目前正在以这种方式获取文件:

@app.route('/get_doc/<filename>')
@login_required
def get_doc(filename):
      sending = {'x-filename': filename}
      response = requests.get('http://<<api_server>>', headers=sending)
      return response.content

The result is that when I click download in the webpage ( http://<<frontend>>/get_doc/20201116003_895083.jpg ), I see the file as text and not downloaded.结果是,当我在网页( http://<<frontend>>/get_doc/20201116003_895083.jpg )中单击下载时,我将文件视为文本而不是下载。 For example, I see a big page full of that:例如,我看到一个很大的页面:

����]ExifII*����

I don't understand if the problem is in the frontend or in the backend.我不明白问题是在前端还是在后端。 In the frontend, I tried with urllib.request.Request or requests.request .在前端,我尝试使用urllib.request.Requestrequests.request Any idea how to manage this kind of download?知道如何管理这种下载吗? Probably is something related to mime interpretation, bytes download or buffer it locally.可能与 mime 解释、字节下载或本地缓冲有关。 Of course, I don't want to download the file in the web-frontend storage.当然,我不想在网络前端存储中下载文件。 I want to redirect it to the visitor.我想将其重定向给访问者。

Here are the headers from GET:以下是 GET 的标头:

{'Content-Disposition': 'attachment; filename=20201116003_895083.jpg', 'Content-Length': '574424', 'Content-Type': 'image/jpeg', 'Last-Modified': 'Tue, 01 Dec 2020 14:04:30 GMT', 'Cache-Control': 'public, max-age=43200', 'Expires': 'Thu, 03 Dec 2020 02:34:51 GMT', 'ETag': '"1606831470.89299-574424-736697678"', 'Date': 'Wed, 02 Dec 2020 14:34:51 GMT', 'Server': 'Werkzeug/1.0.1 Python/3.8.3'}

I'm not sure if this is a good way to architect your application.我不确定这是否是构建应用程序的好方法。 I think the Restful backend is intended to work with a Javascript frontend, rather than a separate Flask app which contacts the 'backend' with the requests library.我认为 Restful 后端旨在与 Javascript 前端一起使用,而不是与requests库联系“后端”的单独 Flask 应用程序一起使用。 I'm not sure how this would behave in a larger app.我不确定这在更大的应用程序中会如何表现。 The requests documentation raises some prod considerations about timeouts for example.例如, requests文档提出了一些关于超时的建议。 You may see some unforseen issues down the line when deploying this with a WSGI server.使用 WSGI 服务器部署它时,您可能会看到一些无法预料的问题。 (imo) (海事组织)

However, with that considered, a quick fix for the actual issue would be to use the flask.send_file function to return the file.但是,考虑到这一点,实际问题的快速解决方法是使用flask.send_file function 来返回文件。 This accepts a file pointer as the first argument, so you'll need to use io.BytesIO to convert the bytes object:这接受文件指针作为第一个参数,因此您需要使用io.BytesIO来转换字节 object:

from flask import send_file
from io import BytesIO

@app.route('/get_doc/<filename>')
@login_required
def get_doc(filename):
      sending = {'x-filename': filename}
      response = requests.get('http://<<api_server>>', headers=sending)
      return send_file(BytesIO(response.content), mimetype='image/jpeg'
          #as_attachment=True
          )

You also need to provide the mimetype argument, as usually send_file guesses the mimetype based on the extension when a string like 'file.jpg' is passed as the first arg.您还需要提供mimetype参数,因为当像'file.jpg'这样的字符串作为第一个参数传递时, send_file通常会根据扩展名猜测 mimetype。 Obviously that can't be done in this case.显然,在这种情况下不能这样做。

You can also pass as_attachment=True if you want the user to receive a download prompt, rather that viewing the image in-browser.如果您希望用户收到下载提示,而不是在浏览器中查看图像,您也可以传递as_attachment=True This is all mentioned in thesend_file docs .这在send_file文档中都提到了。

Again, this feels like a hack.再一次,这感觉就像一个黑客。 Something seems off with using the requests library in this way.以这种方式使用requests库似乎有些不对劲。 Perhaps other SO users will be able to comment further on this.也许其他 SO 用户将能够对此发表进一步评论。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM