我尝试使用 POST 请求发送文件,然后使用 paramiko 将其转发到服务器。我有以下代码:
@app.route("/", methods=['GET', 'POST'])
def upload():
file = request.files['file']
try:
gethostbyname("servername")
except gaierror:
print(gaierror)
exit()
port = 22
if request.method == 'POST':
filePost = request.args.get('filename')
transport = paramiko.Transport("servername", port))
try:
transport.connect(username="user",password="password", hostkey=None)
sftp = paramiko.SFTPClient.from_transport(transport)
except paramiko.ssh_exception.AuthenticationException as e:
print(e)
exit()
path = '/home/'+file.filename
try:
sftp.put(file, path)
except Exception as e:
print(e)
不幸的是,没有上传任何内容。恐怕我必须先保存来自 POST 请求的文件。有可能解决这个问题吗?还是我错过了什么?
我的发布请求中的键/值(使用 Postman):
key:file
value:test.txt
Flask save
SFTPClient.open
。这样您就可以将 HTTP 上传的文件直接流式传输到 SFTP 服务器,而无需将其临时存储在 Web 服务器上。
sftp = paramiko.SFTPClient.from_transport(transport)
path = '/home/'+file.filename
with sftp.open(path, 'w+', 32768) as f:
file.save(f)
有关 32768
参数的目的,请参阅写入使用 Paramiko/pysftp“打开”方法打开的 SFTP 服务器上的文件速度很慢。
强制警告:直接使用低级 Transport
类会绕过 SSH/SFTP 服务器主机密钥验证(您甚至通过
hostkey=None
强制执行)。这是一个安全缺陷。如需正确的解决方案,请使用
SSHClient
API 并参阅Paramiko“未知服务器”。
主要问题是您正在尝试通过 SFTP 传输 POST 参数中的
file
,而
sftp.put
期望来自 FS 的文件路径作为第一个参数。这是一个重新组织的函数,对我有用。您可以注意到,文件首先保存到 FS (
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
),然后将相同的字符串传递到
sftp.put
:
import os
import sys
import paramiko
from werkzeug.utils import secure_filename
from flask import Flask, render_template, redirect, url_for, request, g
UPLOAD_FOLDER = '/tmp'
app = Flask(__name__,
static_url_path='',
static_folder='static')
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
@app.route("/upload", methods=['GET', 'POST'])
def upload():
if request.method == 'POST':
try:
file = request.files['file']
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
transport = paramiko.Transport("sftphosthere", 22)
try:
transport.connect(username="usernamehere", password="passwordhere", hostkey=None)
sftp = paramiko.SFTPClient.from_transport(transport)
except paramiko.ssh_exception.AuthenticationException as e:
return e
path = '/tmp/'+file.filename
try:
sftp.put(os.path.join(app.config['UPLOAD_FOLDER'], filename), path)
return "Sftp OK!"
except Exception as e:
return e
except Exception as e:
return e
else:
return "GET request"
############################################################################################################################
if __name__ == "__main__":
app.run(debug=True, port=8000, host="0.0.0.0")
作为客户端发出POST请求,可以使用curl命令代替Postman:
curl -X POST http://flaskserverhere:8000/upload -F "file=@my_testfile.txt"
在运行之前,您需要在同一目录中准备一个文件(上面命令中的my_testfile.txt
)。