0

我已经子类化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 地址。

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

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

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

更奇怪的是(如您在我do_PUT()BaseHTTPRequestHandler.

4

1 回答 1

0

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

按照@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 不会添加一个!

于 2018-04-12T08:53:37.210 回答