通过 Qt 发送 PUT 请求时错误的请求类型 PUT,适用于 curl

Posted

技术标签:

【中文标题】通过 Qt 发送 PUT 请求时错误的请求类型 PUT,适用于 curl【英文标题】:Bad request type PUT when sending PUT request through Qt, works with curl 【发布时间】:2018-04-11 14:31:05 【问题描述】:

我继承了BaseHTTPRequestHandler 并实现了do_GET()do_POST()do_PUT()

在我将 Qt 应用程序进行测试之前,我认为一切正常。 GET 请求有效,服务器发送一个 XML 文档,其中包含应用程序处理的一些数据。 POST 请求也有效,用于通过 REST 生成测试用例。

至于 PUT,事情看起来很奇怪。

这是服务器端的 PUT 处理程序:

def do_PUT(self):
        """
        Processes PUT request. It can be tested using wget, curl or any
        other tool with support for http PUT. Use this to send reports
        about the current status of device and all of its slave devices

        Example:
            curl -X PUT -d "status=downloading" http://127.0.0.1:8090/so/updateProgress
        """
        print('Processing PUT request...')

        params_parsed = urlparse(self.path)
        params = parse_qs(params_parsed.query)
        if len(params) > 0 or '/so/updateProgress' not in params_parsed.path:
            print('Use "/so/updateProgress" to report on update progress')
            self.__set_headers(data_type='text/html')
            self.send_error(501)
            return

        self.__set_headers(data_type='text/xml')
        report_raw = self.rfile.read(int(self.headers.getheader('Content-length')))
        print('Received report')
        print('Parsing report...')
        # Generate XML from the raw data and validate it
        report = SoRequestHandler.Report.from_xml(report_raw)
        print('Parsing of report complete')
        report.write_to_file(log_path='report_log', append=True)
        self.send_response(200)

在我的 Qt 应用程序中,我有一个名为 ReportPublisher 的类,它从它连接到的所有设备(通过 MQTT)获取一些报告,将报告聚合成一个单一的报告并将其发送到服务器,服务器记录它在文件中:

void ReportPublisher::publishHttpReport(HttpReport report)

    QString reportXml = report.xml().toString();
    if (reportXml.isEmpty())
    
        LOG(ERROR) << "Something went wrong with the generation of HTTP report";
        return;
    

    LOG(INFO) << "Generated report for SO server: " << reportXml;
    QByteArray reportRaw = reportXml.toUtf8();

    QUrl target(this->urlServer);
    target.setPath(this->urlPath);
    QNetworkRequest req(target);
    req.setHeader(QNetworkRequest::ContentTypeHeader, QString("application/xml"));
    this->reply = this->nam->put(req, reportRaw);

    // TODO Read back response (expected code 200)?

我必须诚实。我从未在 Qt 中完成过 PUT 请求,到目前为止我所做的只是 GET 请求,因此在上面的代码中可能存在一些非常基本但很容易发现的错误。

服务器收到的数据是这样的:

<updateProgress xmlns='service.so.de/so'>
    <deviceTypeId>...</deviceTypeId>
    <packageId>...</packageId>
    <version>...</version>
    <status>...</status>
</updateProgress>

如果我像这样使用curl

root@obunit:~$ curl -X PUT -i 'http://192.168.120.61:8090/so/updateProgress' -d "<updateProgress xmlns='service.so.de/so'><deviceTypeId>...</deviceTypeId><packageId>...</packageId><version>...</version><status>...</status></updateProgress>"

其中 192.168.120.61:8090 是 IP 地址和服务器所在/侦听传入请求的端口我没有问题。

但是我得到的数据来自我的 Qt 应用程序

192.168.120.172 - - [11/Apr/2018 15:32:37] code 400, message Bad HTTP/0.9 request type ('PUT')
192.168.120.172 - - [11/Apr/2018 15:32:37] "PUT  HTTP/1.1" 400 -

在我的日志中(192.168.120.172 是运行我的软件的系统的 IP 地址。

据我所知,code 400 表示语法无效,这可能是由于以下两个原因(至少我现在能想到的):

格式错误的数据(无效的 XML、JSON 等) 数据编码不正确,基本等同于格式错误的数据,但来自不同的来源。

我尝试使用QDomDocument::toByteArray(int i) 将生成的XML 文档转换为QByteArray。我还尝试(如您在代码中看到的那样)将文档转换为 QString,然后转换为 UTF-8 QByteArray,但我无法让我的服务器处理数据。

更奇怪的是(正如您在我的do_PUT() 中看到的那样)我的 PUT 处理程序从打印一条消息开始,该消息从未出现在日志中,因此问题来自BaseHTTPRequestHandler 代码中更深的地方。

【问题讨论】:

您是否尝试过运行 Wireshark 来查看正在发送哪些数据?应该能够发现差异。 @MrEricSir 感谢您的帮助。问题已解决(有关详细信息,请参阅我的答案)。 :) 【参考方案1】:

这个问题很简单,但很烦人。

按照@MrEricSir 的建议,我确实使用了 Wireshark,只是为了发现它得到了一些奇怪的 TCP 重传。重新传输通常是由于网络拥塞而发生的,在我的情况下这是不可能的,但它确实表明网络问题与我发送的 XML 内容无关。

所以我再次开始了我的远程调试会话,并查看了我发出 PUT 请求的位置。它就在那里!基本 URL (IP:PORT) 和路径之间缺少 /。所以不是

PUT 192.168.120.61:8090/so/updateProgress

我在做

PUT 192.168.120.61:8090so/updateProgress

这最终导致 PUT 请求根本不成功(因此代码为 400)。

只是对以后阅读本文的任何人的提示 - 每当您使用 QUrl::setPath(QString) 手动设置该路径时

QUrl target(this->urlServer);
target.setPath(this->urlPath);

始终确保您作为路径传递的字符串以/ 开头,因为Qt 不会添加一个!

【讨论】:

以上是关于通过 Qt 发送 PUT 请求时错误的请求类型 PUT,适用于 curl的主要内容,如果未能解决你的问题,请参考以下文章

[尝试发送其他语言的PUT请求时出现服务器错误

在没有原始数据的情况下重新发送 post/put 请求

Laravel CSRF 令牌不匹配异常。通过 jQuery ajax 向资源路由发送“Put”请求

使用 Coldfusion/Railo 向 Mailchimp API v3.0 发送 PUT 请求时出现 401 未经授权的错误

“使用邮递员放入适应性时不支持的媒体类型

无法从客户端向 Fastify 后端发出 PUT 请求 [重复]