基于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
相关产品推荐
相关产品推荐

