关于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 | 总结

好好干,总得练习两年半

在这里插入图片描述

相关内容

热门资讯

“我要打10个”的伊朗,缺油了... 如果说两周前,伊朗军方还在电视台上拍着胸脯保证“一切正常,我们赢麻了”,那么现在,这层窗户纸算是被彻...
REDMI K90 Max发布... 4 月 21 日,REDMI K90 Max 正式发布。作为 REDMI K 系列全新成员,REDM...
A股,突变!七大巨头,集体异动... 市场明显起了变化!早上,紫金矿业和宁德时代两大巨头都在发布利好之后意外回落,与此同时,有色和电池板块...
“农夫”们才入局,补水啦已经签... 文 | 陶魏斌2026年世界杯开赛在即,补水啦官宣了自己的品牌代言人——姆巴佩,当今足球世界的顶级球...
新市场扭亏、国内转型阵痛 极兔... 独立 稀缺 穿透仍有不少硬仗要打作者:闻道编辑:李莉风品:一然来源:铑财——铑财研究院新曲线越烧越旺...
盘后突发利空!油价涨破100,... 今天的行情再次应了那句话:不要光站在那里,要站在光里!隔壁港股大跌,A股低开高走,上证指数站上410...
纠结的万华化学:不论业绩如何,... 在周期股里,万华化学这两年的表现有点别扭,化工赛道热门企业华鲁恒升、新和成、卫星化学等纷纷在今年创出...
手机涨价潮来袭,OPPO刘作虎... 4月21日,OPPO正式发布Find X9s Pro与Find X9 Ultra 影像双旗舰新品。作...
航空业“油荒”危机将至:海湾出... 财联社4月22日讯(编辑 刘靖怡)随着全球航运咽喉霍尔木兹海峡因美伊对峙被封锁,海湾地区对国际市场的...
调研|平安银行对公和零售信贷投... 截至今年3月末,创业板上市公司占A股上市公司总数1/4,总市值近18万亿元,是全球最具活力的市场之一...