You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于gRPC的Python帖子微服务:Firebase媒体上传失败求助

解决gRPC帖子微服务Firebase Storage媒体上传问题

问题核心原因

当前代码存在多处逻辑错误导致媒体文件无法正常上传:

  • 测试脚本仅传递文件名的字节串,而非实际文件的二进制内容
  • 服务端错误调用request.media[0].decode获取文件名,且仅处理单个媒体文件
  • 服务端上传时直接传递gRPC消息对象而非文件二进制数据
  • 数据库存储原始媒体数据,违背"媒体存Storage、数据库存路径"的设计逻辑

修正后的服务端代码

def CreatePost(self, request, context):
    try:
        error_message = self.decode_token(request.token, request.username)
        if error_message:
            app.logger.warning(f'CreatePost: {error_message}')
            return post_service_pb2.Response(message=error_message)

        post_id = str(int(datetime.timestamp(datetime.now())))
        media_metadata = []
        
        # 建议将Storage客户端初始化放在服务启动时,避免重复创建
        storage_client = storage.Client()
        bucket = storage_client.bucket(BUCKET_NAME)

        # 循环处理所有媒体文件
        for idx, media in enumerate(request.media):
            filename = media.filename
            file_data = media.data
            content_type = media.content_type
            
            # 构造Storage中的唯一文件路径
            blob_name = f'media/{post_id}/{idx}_{filename}'
            blob = bucket.blob(blob_name)
            
            # 上传二进制文件数据,并指定内容类型
            blob.upload_from_string(file_data, content_type=content_type)
            
            # 收集媒体元数据存入数据库(可根据需求调整字段)
            media_metadata.append({
                'type': content_type,
                'filename': filename,
                'storage_path': blob_name,
                'url': blob.public_url  # 可选:获取公开访问URL
            })

        # 构造帖子数据,仅存储媒体元数据而非原始内容
        post_data = {
            'text': request.text,
            'timestamp': str(datetime.now()),
            'username': request.username,
            'media': media_metadata
        }

        db.reference('posts').child(post_id).set(post_data)

        app.logger.debug(f'CreatePost: Post created successfully (ID: {post_id})')
        return post_service_pb2.Response(message='Post created successfully')

    except ValueError as e:
        app.logger.error(f'CreatePost: Failed to create post: {str(e)}')
        return post_service_pb2.Response(message=f'Failed to create post: {str(e)}')
    except Exception as e:
        app.logger.exception(f'CreatePost: An unexpected error occurred: {str(e)}')
        return post_service_pb2.Response(message=f'An unexpected error occurred: {str(e)}')

修正后的测试脚本代码

def test_create_post(stub, token, username):
    # 读取本地文件的二进制内容
    def read_file(file_path):
        with open(file_path, 'rb') as f:
            return f.read()

    # 准备测试用媒体文件
    test_media = [
        {
            'filename': 'image1.jpg',
            'content_type': 'image/jpeg',
            'data': read_file('./test_files/image1.jpg')
        },
        {
            'filename': 'video1.mp4',
            'content_type': 'video/mp4',
            'data': read_file('./test_files/video1.mp4')
        }
    ]

    # 转换为gRPC Media消息对象
    media_messages = [
        post_service_pb2.Media(
            filename=item['filename'],
            content_type=item['content_type'],
            data=item['data']
        ) for item in test_media
    ]

    request = post_service_pb2.CreatePostRequest(
        token=token,
        username=username,
        text="This is a test post.",
        media=media_messages
    )
    response = stub.CreatePost(request)
    print(response.message)

配套gRPC Proto定义补充

确保你的.proto文件包含正确的消息结构:

syntax = "proto3";

package post_service;

message Media {
    string filename = 1;
    string content_type = 2;
    bytes data = 3;
}

message CreatePostRequest {
    string token = 1;
    string username = 2;
    string text = 3;
    repeated Media media = 4;
}

message Response {
    string message = 1;
}

service PostService {
    rpc CreatePost(CreatePostRequest) returns (Response);
}

内容的提问来源于stack exchange,提问作者Nam Anh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 00:20:32