关于postman测试通过civetweb实现的HTTP接口报错Error: Parse Error: Expected HTTP/问题
创始人
2025-05-28 19:29:06
0

最近需要新增一个 REST API 的功能,然后使用到常用的开源库 civetweb 来实现这个功能

在这里插入图片描述

文章目录

      • 01 | 问题描述
      • 02 | 问题追踪
      • 03 | 问题原因
      • 04 | 问题解决
      • 05 | 总结

测试HTTP接口时,发现 postman 响应报错 ** Error: Parse Error: Expected HTTP/**

01 | 问题描述

使用 postman 测试使用开源库 civetweb 实现的 HTTP 接口时,postman 报错 Error: Parse Error: Expected HTTP/

在这里插入图片描述

02 | 问题追踪

错误信息 Error: Parse Error: Expected HTTP/有一个关键字:Parse,简要的说明了响应报文中存在解析校验错误的模块,那么现在问题就变成了找到报文中那里出错导致解析/校验失败

网络相关问题解决三步骤:

  1. 检查自己响应报文处代码
```cpp
void send_Http_cmd_error_rsp(struct mg_connection *conn)
{if (NULL == conn){return;}Json::Value root;root["errorCode"] = 400;root["errorMsg"] = "Bad Request";string resBody = root.toStyledString();int resLen = resBody.length();printf("resLen = [%d], resBody = %s\n", resLen, resBody.c_str());int ret = mg_printf(conn, "%s","HTTP/1.1 400 Bad Request\r\n""Cache-Control: no-cache\r\n""Content-Type: text/html;charset=utf-8\r\n");printf("ret = [%d]", ret);ret = mg_printf(conn, "Connection: %s\r\n", "keep-alive");printf("ret = [%d]", ret);ret = mg_printf(conn, "Content-Length: %d\r\n\r\n", resLen);printf("ret = [%d]", ret);ret = mg_printf(conn, "%s", resBody.c_str());printf("ret = [%d]", ret);
}
```检查中并没有发现函数用错、变量赋值错误、传值错误等问题,而且在每一次调用`mg_printf()`的时候我都把返回值打印了,并没有执行出错的情况,那么基本可以排除了代码逻辑问题
  1. Wireshark 抓包分析
这里通过 Wireshark 捕抓 ARM 和 PC 之间交互时的网络数据包![在这里插入图片描述](https://img-blog.csdnimg.cn/d18e200e3ba645b1a1f48bb77e2d67ea.png#pic_center)

在这里插入图片描述

从上面抓包获取到的图可以看到,交互时产生的数据包确实存在问题,HTTP对应的数据包尾缀`Malformed Packet`代表的意思是*畸形包(在这里畸形包就是不符合各层协议规范,无法被Wireshark解析的错误数据包)*,这里就开始找到异常现象了

在这里插入图片描述

通过进一步的追踪这个HTTP数据包,发现HTTP流层数据是我所发送的数据无误,但是TCP流层却多出了其他数据
  • 那么多出这坨东西,为什么会导致解析失败呢?

    回头看了下代码里我指定的 Context-Length字段长度是我发送数据的长度,那么现在多出来的数据就导致了实际长度比我预设的长度要大,所以这个数据包校验不通过,认为是不合法,是个畸形包

  • 为什么我没有发送这坨东西,但是它却真真实实的出现在了数据包里?

    因为一开始已经确定了自己并没有发送这坨多出来的数据,而且这坨数据显得十分的官方化,所以基本上确定这是源码本身自己处理发送的数据,所以问题最后就是找到这个多出来的数据是在源码哪个位置进行处理发送的

  1. 开源库源码解析
> 众所周知 HTTP 状态码 404 对应的错误消息就是 Not Found

因为这个错误出现的位置是在回复响应报文阶段,所以在查看源码解析的时候,可以大大的缩小范围,直接找 request_handler的文件进行搜索mg_printf() Not Found | Not found关键词来确定问题代码处。
civetweb.c文件搜索 Not Foundmg_printf()找到了内置的发送错误消息的函数mg_send_http_error()mg_send_http_error_impl()

	intmg_send_http_error(struct mg_connection *conn, int status, const char *fmt, ...){va_list ap;int ret;va_start(ap, fmt);ret = mg_send_http_error_impl(conn, status, fmt, ap);va_end(ap);return ret;}

mg_send_http_error_impl()函数最后找到了这个消息发送的代码

   /* HTTP responses 1xx, 204 and 304 MUST NOT send a body */if (has_body) {/* For other errors, send a generic error message. */const char *status_text = mg_get_response_code_text(conn, status);mg_printf(conn, "Error %d: %s\n", status, status_text);mg_write(conn, errmsg_buf, strlen(errmsg_buf));} else {/* No body allowed. Close the connection. */DEBUG_TRACE("Error %i", status);}

解析这个函数了解到,Error 404: Not Found 这个消息是通过传进来的状态码 404,调用mg_get_response_code_txt()获取到的,而 Not found 这个消息是通过外部传进来的,那么就可以查找调用最外层函数mg_send_http_error(conn, 404, "%s", "Not found)的地方所以确定了这多出来的消息是调用这个函数发送的,那么在它的最外层mg_send_http_error()函数进行查找在哪里设置了 404 Not found
在找到的三处地方,通过把 Not found 修改成其他消息,重新走一下分析过程,最终确定了调用位置是handle_request()函数处

在这里插入图片描述

   /* 11. File does not exist, or it was configured that it should be* hidden */if (!is_found || (must_hide_file(conn, path))) {mg_send_http_error(conn, 404, "%s", "fuck fuck2");return;}

我对上面这段代码的理解大概是

> 如果响应消息中需要的配置信息不存在或者需要被隐藏的情况下,会触发自动发送 404 Not found 的动作

03 | 问题原因

综上所述:

  1. 问题表面上是效应报文中实际数据长度大于设定的Context-Length值,导致数据包错误

  2. 问题实际上是在执行我设定的mg_printf()之前,civetweb 本身就已经在 handle_request()处做了响应处理,这时候自然识别到的报文是没有任何响应头字段的,所以触发了上面自动发送 404 Not Found 的动作

04 | 问题解决

  • 如果仅针对表面现象

    可以直接修改响应头中的 Content-Length 值,使其足够大即可,实验证明这个方法确实可以(网上其他碰到类似问题的解决方法也都采用的是这个),但是如果下次触发的是其他奇奇怪怪的动作,这个值还是不够大呢?

    所以还是得从根源出发,解决问题

  • 根源解决

    既然我调用 mg_printf()处理完成前, civetweb 本身的 handle_request()就已经开始运作了,那么只要确保*等我执行完mg_printf()之后再让handle_request()进行运作就好

    处理方式就是在代码的最后加上一定的延时,确保我的消息已经完成了即可,我这里设置了10秒的延时

    void send_Http_cmd_error_rsp(struct mg_connection *conn)
    {if (NULL == conn){return;}Json::Value root;root["errorCode"] = 400;root["errorMsg"] = "Bad Request";string resBody = root.toStyledString();int resLen = resBody.length();printf("resLen = [%d], resBody = %s\n", resLen, resBody.c_str());int ret = mg_printf(conn, "%s","HTTP/1.1 400 Bad Request\r\n""Cache-Control: no-cache\r\n""Content-Type: text/html;charset=utf-8\r\n");printf("ret = [%d]", ret);ret = mg_printf(conn, "Connection: %s\r\n", "keep-alive");printf("ret = [%d]", ret);ret = mg_printf(conn, "Content-Length: %d\r\n\r\n", resLen);priintf("ret = [%d]", ret);ret = mg_printf(conn, "%s", resBody.c_str());printf("ret = [%d]", ret);sleep(10);
    }
    

05 | 总结

好好干,总得练习两年半

在这里插入图片描述

相关内容

热门资讯

同力股份:无人驾驶产品目前已完... 新京报贝壳财经讯(记者黄鑫宇)2025年12月26日晚,北交所上市公司陕西同力重工股份有限公司(即“...
新消费周报 | 淘宝闪购开通无... 《CBNData新消费周报》精选本周新消费领域最新动态,公司头条、消费风向、智能创新、营销动态、可持...
穿越波动的稳健之选:优质可转债... 作者:烟雨导语:在当下复杂多变的市场环境中,可转债因其"股债双性"的独特优势,成为投资者平衡风险与收...
6天4板!华联控股拟12.35... Arizaro项目LCE(碳酸锂当量)总资源量概要。 图源:华联控股公告本报记者 李贝贝 上海报道1...
触及重大违法行为,或将被退市!... 本文来源:时代周报 作者:林昀肖12月26日,*ST长药(300391.SZ)公告称,公司因涉嫌定期...
独家揭秘!新股未上市先套现,中... 暗盘交易的本质是一场对赌。“蘅东光每股190元买断”。近日,随着北交所新股蘅东光中签结果出炉,券商中...
科技富豪财富暴增:马斯克身价上... 2025年人工智能投资热潮推动了美国最富有的科技富豪净资产飙升。但随着市场对人工智能泡沫担忧的增长,...
马思唯献唱NBA名人赛 尼克杨... 近日,2025成都聚星名人赛在成都五粮液体育中心举行。现场,四川籍说唱歌手马思唯担任助演嘉宾,倾情现...
一家老牌VC决定申请破产 在一级市场中,风险投资机构主动申请破产实属罕见。但近日,一家美国老牌VC却做出了这一出人意料的决定。...
300391爆雷!连续三年财务... 本报(chinatimes.net.cn)记者帅可聪 北京报道“全仓进的,这回真不知道该怎么办了。”...