Cloud Function返回400 Bad Request问题排查求助
问题描述
我写了一段HTTP触发的Cloud Function代码,用来提取GCS中指定zip文件的内容并上传回GCS。代码如下:
import functions_framework import os import tempfile import zipfile from google.cloud import storage def extract_zip(event): """Cloud Function to extract contents of a zip file uploaded to GCS.""" # Specify your GCS bucket name bucket_name = "deepcare-dataset" print(bucket_name) # Extract information from the event file_name = event["name"] file_path = f"gs://{bucket_name}/{file_name}" print(file_path) # Set up a temporary directory to extract files temp_dir = tempfile.mkdtemp() # Create a storage client storage_client = storage.Client() print('Downloading...') # Download the zip file from GCS blob = storage_client.get_bucket(bucket_name).get_blob(file_name) download_path = os.path.join(temp_dir, file_name) blob.download_to_filename(download_path) print('Extracting...') # Extract the contents of the zip file with zipfile.ZipFile(download_path, 'r') as zip_ref: zip_ref.extractall(temp_dir) print('Uploading...') # Upload the extracted files back to GCS for extracted_file in os.listdir(temp_dir): extracted_file_path = os.path.join(temp_dir, extracted_file) destination_blob_name = f"{file_name[:-4]}/{extracted_file}" # Upload the extracted file to GCS storage_client.get_bucket(bucket_name).blob(destination_blob_name).upload_from_filename(extracted_file_path) print(f'Uploaded for:', destination_blob_name) # Clean up the temporary directory os.remove(download_path) os.rmdir(temp_dir) print(f"Extraction and upload completed for {file_name}") @functions_framework.http def hello_http(request): """HTTP Cloud Function. Args: request (flask.Request): The request object. <https://flask.palletsprojects.com/en/1.1.x/api/#incoming-request-data> Returns: The response text, or any set of values that can be turned into a Response object using `make_response` <https://flask.palletsprojects.com/en/1.1.x/api/#flask.make_response>. """ request_json = request.get_json(silent=True) request_args = request.args if request_json and 'name' in request_json: name = request_json['name'] if name == 'myzip.zip': extract_zip(request_args) elif request_args and 'name' in request_args: name = request_args['name'] if name == 'myzip.zip': extract_zip(request_args) else: name = 'World' return 'Hello {}!'.format(name)
当POST请求体为{"name":"myzip.zip"}时,Cloud Function返回400 Bad Request;但请求体为{"name":"foo"}时返回200 OK。日志仅显示警告,无明确错误原因:
{ "insertId": "656b0fa30002f03d0c947a91", "httpRequest": { "requestMethod": "POST", "requestUrl": "https://asia-southeast2-***.cloudfunctions.net/function-1", "requestSize": "464", "status": 400, "responseSize": "819", "userAgent": "PostmanRuntime/7.34.0", "remoteIp": "104.28.254.47", "serverIp": "216.239.36.54", "latency": "0.005019129s", "protocol": "HTTP/1.1" }, "resource": { "type": "cloud_run_revision", "labels": { "revision_name": "function-1-00001-qid", "location": "asia-southeast2", "service_name": "function-1", "project_id": "***", "configuration_name": "function-1" } }, "timestamp": "2023-12-02T11:06:11.180972Z", "severity": "WARNING", "labels": { "goog-managed-by": "cloudfunctions", "instanceId": "0087599d42c23459cbb07b0680f42627a501194e4825c912c5119b703c25894fe2d5caf7a1bbe0ce42006b2c6f646d2cd6ec68f6f5fb2ad91fa39a17e6eaa78789" }, "logName": "projects/***/logs/run.googleapis.com%2Frequests", "trace": "projects/***/traces/98c21d5c3145fa7af9b5bc5f2d53b523", "receiveTimestamp": "2023-12-02T11:06:11.194091644Z", "spanId": "14357157746819527854", "traceSampled": true }
怀疑extract_zip函数出错,但无法确定400响应来源,需要调试排查思路。
调试排查思路
- 添加错误捕获与详细日志:在
extract_zip函数外层包裹try-except块,捕获所有异常并打印异常类型、错误信息及堆栈跟踪;同时在hello_http调用extract_zip的位置也增加异常处理,避免未捕获异常直接触发HTTP错误。示例:def extract_zip(event): try: # 原函数代码 except Exception as e: print(f"extract_zip错误: {type(e).__name__} - {str(e)}") import traceback traceback.print_exc() raise # 在hello_http中调用时: if name == 'myzip.zip': try: extract_zip(request_json if request_json else request_args) except Exception as e: print(f"调用extract_zip失败: {e}") - 修复参数传递错误:当前代码中,当请求体是JSON格式时,错误地将
request_args(URL参数对象)传入extract_zip,但此时request_args为空,会触发KeyError。应改为传递request_json:if request_json and 'name' in request_json: name = request_json['name'] if name == 'myzip.zip': extract_zip(request_json) - 验证GCS权限:确认Cloud Function的服务账号拥有目标GCS存储桶的
storage.objects.get(下载权限)和storage.objects.create(上传权限),可临时添加Storage Object Admin角色测试,排除权限问题。 - 修复临时目录清理逻辑:
os.rmdir(temp_dir)只能删除空目录,解压后目录内存在提取的文件,会触发OSError。改用shutil.rmtree(temp_dir)递归删除目录及内容:import shutil # 替换原清理代码 shutil.rmtree(temp_dir) - 查看完整函数日志:不要仅查看请求日志,前往Cloud Function的函数日志页面,这里会包含
print语句输出和异常堆栈信息,可直接定位错误点。 - 本地模拟测试:使用
functions-framework在本地运行函数,模拟POST请求,直接观察控制台输出的错误信息,本地测试时可使用GCS密钥文件复现完整流程。
内容的提问来源于stack exchange,提问作者Muhammad Ikhwan Perwira
相关产品推荐
相关产品推荐

