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

Python 3.9环境下使用POST请求发送JSON数据时出现JSONDecodeError问题求助

解决Python POST请求中的JSONDecodeError问题

先帮你定位下错误根源:你看到的JSONDecodeError: Expecting value: line 1 column 1 (char 0),本质是你尝试解析一个空的响应内容。当Callminer服务器返回的响应没有JSON数据(比如返回204 No Content状态码,或者响应体为空)时,调用response.json()就会触发这个错误——因为没有任何可解析的JSON值。

另外,我注意到你代码里的json.loads(metadata_body)步骤也有潜在问题:你打印的内容是Python字典的字符串表示(用单引号包裹键和值),但标准JSON要求必须用双引号。如果metadata_body就是这种单引号格式的字符串,json.loads()其实会直接报错,只是当前的响应解析错误先触发了。

下面是具体的解决方案和修改后的代码:

核心修复点

1. 先处理HTTP请求状态,再安全解析响应JSON

不要直接调用response.json(),应该先检查请求是否成功,再判断响应体是否非空,最后用异常处理包裹JSON解析逻辑:

  • 用response.raise_for_status()主动抛出HTTP错误(比如4xx/5xx状态码),提前捕获请求失败的情况。
  • 先判断response.text是否非空,再尝试解析JSON,避免空内容导致的解码错误。

2. 修正metadata_body的处理逻辑

如果self.__fill_metadata()返回的是Python字典列表,你完全不需要把它转成字符串再用json.loads()解析回来——requests.post的json参数可以直接接收字典,它会自动帮你转成标准JSON格式发送。
如果metadata_body确实是单引号格式的字符串(比如你打印的那种),不要用json.loads(),改用ast.literal_eval()来解析Python风格的字典字符串(这个方法支持单引号)。

修改后的完整代码

import json
import ast
import requests
from requests.structures import CaseInsensitiveDict
from base64 import b64encode

# 你的其他变量定义(CONSUMER_USERNAME、CONSUMER_PASSWORD等)

consumer_identifiers = bytes(f"{CONSUMER_USERNAME}:{CONSUMER_PASSWORD}", encoding='utf-8')
headers: requests.structures.CaseInsensitiveDict = CaseInsensitiveDict()
headers["Basic-Authorization"] = f"Basic {b64encode(consumer_identifiers).decode('ascii')}"
headers["Authorization"] = f"Bearer {self.__token['access_token']}"
metadata_body_list = self.__fill_metadata()
logger.info("Start send metadata to Callminer...")
logger.info(f"The number of metadata sent is : {len(metadata_body_list)}")
assert METADATA_INGESTION_URL is not None

for metadata_body in metadata_body_list:
    # 情况1:如果fill_metadata返回的是Python字典,直接使用
    json_metadata_body = metadata_body
    
    # 情况2:如果metadata_body是单引号格式的字符串,启用下面这行替换上面的内容
    # json_metadata_body = ast.literal_eval(metadata_body)
    
    try:
        response = requests.post(METADATA_INGESTION_URL, headers=headers, json=json_metadata_body)
        # 先检查HTTP状态码,触发4xx/5xx错误
        response.raise_for_status()
        
        # 安全解析响应JSON
        response_json = None
        if response.text.strip():
            try:
                response_json = response.json()
            except json.JSONDecodeError:
                logger.warning("Server returned non-JSON response body")
        
        if response_json:
            # 注意:这里的CorrelationId首字母大写,你打印的字典里是Correlationid(小写id),要匹配服务器返回的字段名
            if "CorrelationId" in response_json and "MiningId" in response_json and \
                    response_json["CorrelationId"] in str(metadata_body):
                logger.debug(f"Response POST request {response_json}")
            else:
                raise RuntimeError(
                    f"Error occurred when sending metadata to Callminer.\n Response: {response_json}.")
        else:
            logger.debug("Received valid empty response from Callminer")
            
    except requests.exceptions.HTTPError as e:
        raise RuntimeError(f"HTTP Error occurred: {str(e)}")
    except Exception as e:
        raise RuntimeError(f"Unexpected error: {str(e)}")

logger.info("End of sending metadata.")

额外提示

我注意到你打印的请求体里是Correlationid(小写id),但代码里判断的是response_json["CorrelationId"](大写Id),要确保字段名和服务器返回的完全一致,避免误判错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 23:43:11