关于postman测试通过civetweb实现的HTTP接口报错Error: Parse Error: Expected HTTP/问题
创始人
2025-05-28 20:43:49
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 | 总结

好好干,总得练习两年半

在这里插入图片描述

相关内容

热门资讯

保存时出现了1个错误,导致这篇... 当保存文章时出现错误时,可以通过以下步骤解决问题:查看错误信息:查看错误提示信息可以帮助我们了解具体...
汇川伺服电机位置控制模式参数配... 1. 基本控制参数设置 1)设置位置控制模式   2)绝对值位置线性模...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
表格中数据未显示 当表格中的数据未显示时,可能是由于以下几个原因导致的:HTML代码问题:检查表格的HTML代码是否正...
本地主机上的图像未显示 问题描述:在本地主机上显示图像时,图像未能正常显示。解决方法:以下是一些可能的解决方法,具体取决于问...
表格列调整大小出现问题 问题描述:表格列调整大小出现问题,无法正常调整列宽。解决方法:检查表格的布局方式是否正确。确保表格使...
不一致的条件格式 要解决不一致的条件格式问题,可以按照以下步骤进行:确定条件格式的规则:首先,需要明确条件格式的规则是...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...