使用 python 从 az 函数进行 FTP 列表、下载、上传

问题描述 投票:0回答:1

上午 8:51:19 收到此错误 |痕迹 @8F596749-638656982249418103 下载或归档文件时出错:EOF o...rred 违反协议(_ssl.c:2706),当我向 az 函数发送请求时,我使用基于 tls 加密的显式 ftp,这是我的代码: import azure.functions as功能

import ftplib
import json
import base64
import io
import ssl

def main(req: func.HttpRequest) -> func.HttpResponse:
    try:
        params = req.get_json()
        host = params.get('host')
        port = params.get('port', 21)
        username = params.get('username')
        password = params.get('password')
        remote_dir = params.get('remote_dir')
        action = params.get('action', 'list')
        filename = params.get('filename')
        file_content = params.get('file_content')
        archive = params.get('archive', 'no')

        print(f"Received request: Action={action}, Host={host}, Port={port}, Username={username}, Remote Dir={remote_dir}, Archive={archive}")

        if action == 'list':
            files = list_ftp_files(host, port, username, password, remote_dir)
            if files:
                print(f"Successfully listed {len(files)} files")
                return func.HttpResponse(json.dumps({"success": True, "files": files}), mimetype="application/json")
            else:
                print("Failed to retrieve files")
                return func.HttpResponse(json.dumps({"success": False, "error": "Failed to retrieve files"}), mimetype="application/json")
        
        elif action == 'download':
            if not filename:
                print("Download requested but filename not provided")
                return func.HttpResponse(json.dumps({"success": False, "error": "Filename not provided"}), mimetype="application/json")
            
            print(f"Attempting to download file: {filename}")
            try:
                file_content, archived = download_ftp_file(host, port, username, password, remote_dir, filename, archive.lower() == 'yes')
                if file_content:
                    encoded_content = base64.b64encode(file_content).decode('utf-8')
                    print(f"Successfully downloaded file: {filename}, Size: {len(file_content)} bytes, Archived: {archived}")
                    return func.HttpResponse(json.dumps({
                        "success": True, 
                        "filename": filename, 
                        "content": encoded_content,
                        "size": len(file_content),
                        "archived": archived
                    }), mimetype="application/json")
                else:
                    print(f"Failed to download file: {filename}")
                    return func.HttpResponse(json.dumps({"success": False, "error": f"Failed to download file {filename}"}), mimetype="application/json")
            except Exception as e:
                print(f"Error during file download: {str(e)}")
                return func.HttpResponse(json.dumps({"success": False, "error": f"Error downloading file {filename}: {str(e)}"}), mimetype="application/json")
        
        elif action == 'upload':
            if not filename or not file_content:
                print("Upload requested but filename or file content not provided")
                return func.HttpResponse(json.dumps({"success": False, "error": "Filename and file content are required for upload"}), mimetype="application/json")
            
            print(f"Attempting to upload file: {filename}")
            try:
                success = upload_ftp_file(host, port, username, password, remote_dir, filename, file_content)
                if success:
                    print(f"Successfully uploaded file: {filename}")
                    return func.HttpResponse(json.dumps({"success": True, "message": f"File {filename} uploaded successfully"}), mimetype="application/json")
                else:
                    print(f"Failed to upload file: {filename}")
                    return func.HttpResponse(json.dumps({"success": False, "error": f"Failed to upload file {filename}"}), mimetype="application/json")
            except Exception as e:
                print(f"Error during file upload: {str(e)}")
                return func.HttpResponse(json.dumps({"success": False, "error": f"Error uploading file {filename}: {str(e)}"}), mimetype="application/json")
        
        else:
            print(f"Invalid action requested: {action}")
            return func.HttpResponse(json.dumps({"success": False, "error": "Invalid action"}), mimetype="application/json")

    except Exception as e:
        print(f"Unexpected error in main function: {str(e)}")
        return func.HttpResponse(json.dumps({"success": False, "error": f"An unexpected error occurred: {str(e)}"}), mimetype="application/json")


def connect_ftp(host, port, username, password):
    try:
        # Create a context that doesn't verify certificates
        context = ssl.SSLContext(ssl.PROTOCOL_TLS)
        context.check_hostname = False
        context.verify_mode = ssl.CERT_NONE

        # Establishing a secure FTP_TLS connection with custom SSL context
        ftp = ftplib.FTP_TLS()
        ftp.context = context  # Assign the modified context to FTP_TLS
        ftp.connect(host, port, timeout=60)
        ftp.login(username, password)
        ftp.prot_p()  # Enable data connection encryption
        ftp.set_pasv(True)  # Use passive mode for secure connections
        return ftp
    except Exception as e:
        print(f"FTP connection error: {e}")
    return None


def list_ftp_files(host, port, username, password, remote_dir):
    ftp = connect_ftp(host, port, username, password)
    if not ftp:
        print("Failed to establish FTP connection")
        return None

    try:
        print(f"Changing to directory: {remote_dir}")
        ftp.cwd(remote_dir)
        print("Successfully changed directory")

        print("Listing files...")
        files = ftp.nlst()
        print(f"Files retrieved: {files}")
        return files
    except Exception as e:
        print(f"Error listing files: {str(e)}")
    finally:
        if ftp:
            try:
                ftp.quit()
                print("FTP connection closed")
            except:
                print("Error closing FTP connection")
    return None


def download_ftp_file(host, port, username, password, remote_dir, filename, archive):
    ftp = connect_ftp(host, port, username, password)
    if not ftp:
        print("Failed to establish FTP connection for download")
        return None, False

    try:
        print(f"Changing to directory: {remote_dir}")
        ftp.cwd(remote_dir)
        print("Successfully changed directory")

        print(f"Initiating download of {filename}")
        file_content = io.BytesIO()
        ftp.retrbinary(f"RETR {filename}", file_content.write)
        print(f"Download completed. File size: {len(file_content.getvalue())} bytes")
        
        archived = False
        if archive:
            archive_dir = "Archive"
            try:
                ftp.cwd(archive_dir)
            except ftplib.error_perm:
                ftp.mkd(archive_dir)
            ftp.cwd('..')

            print(f"Moving file to Archive: {filename}")
            ftp.rename(filename, f"{archive_dir}/{filename}")
            print(f"File {filename} moved to Archive successfully")
            archived = True
        
        return file_content.getvalue(), archived
    except Exception as e:
        print(f"Error downloading or archiving file: {str(e)}")
        raise
    finally:
        if ftp:
            try:
                ftp.quit()
                print("FTP connection closed")
            except:
                print("Error closing FTP connection")


def upload_ftp_file(host, port, username, password, remote_dir, filename, file_content):
    ftp = connect_ftp(host, port, username, password)
    if not ftp:
        print("Failed to establish FTP connection for upload")
        return False

    try:
        print(f"Changing to directory: {remote_dir}")
        ftp.cwd(remote_dir)
        print("Successfully changed directory")

        print(f"Initiating upload of {filename}")
        ftp.storbinary(f"STOR {filename}", io.BytesIO(base64.b64decode(file_content)))
        print(f"Upload completed.")
        return True
    except Exception as e:
        print(f"Error uploading file: {str(e)}")
        raise
    finally:
        if ftp:
            try:
                ftp.quit()
                print("FTP connection closed")
            except:
                print("Error closing FTP connection")

上午 8:51:19 收到此错误 |痕迹 @8F596749-638656982249418103 下载或存档文件时出错:EOF o...rred 违反协议 (_ssl.c:2706),当我向 az 函数发送请求时,我使用基于 tls 加密的显式 ftp,

python azure function ftps
1个回答
0
投票

下载或归档文件时出错:EOF 发生违反协议:-

根据Microsoft Q&A,SSL连接突然关闭时会出现EOF错误协议问题,可能是网络端问题或服务器端问题。请检查以下内容以解决问题。

首先,你可以尝试升级python相关的包,同时检查是否已经安装了最新的python并与系统兼容

此外,有时问题可能是由于套接字需要自动包装 ssl,因为存在隐式 FTPS 连接。请参阅 @hynekcer 的 SO 以获取类似信息。

Python套接字连接文档中所述,您可以尝试将SSL上下文设置为

context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
专门为客户端连接而存在,可能有助于避免此处的冲突。

try:
        # Create a context that doesn't verify certificates
        context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
        context.check_hostname = False
        context.verify_mode = ssl.CERT_NONE

        # Establishing a secure FTP_TLS connection with custom SSL context
        ftp = ftplib.FTP_TLS()
        ftp.context = context  # Assign the modified context to FTP_TLS
        ftp.connect(host, port, timeout=60)
        ftp.login(username, password)
        ftp.prot_p()  # Enable data connection encryption
        ftp.set_pasv(True)  # Use passive mode for secure connections
        return ftp
    except Exception as e:
        print(f"FTP connection error: {e}")
    return None

另请检查

portal >> function app
出站安全规则虚拟网络是否允许流向 FTP 服务器(TCP 端口 21)的流量。

© www.soinside.com 2019 - 2024. All rights reserved.