1.使用 Poco::Net::HTMLForm
使用 Poco::Net::HTMLForm 获取 数据的方式如下:
virtual void handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override
{
Poco::Net::HTMLForm form(req, req.stream());
for(const auto &it : form)
{
//遍历 form 数据
std::cout << it.first << ":" << it.second << std::endl;
}
}
Poco::Net::HTMLForm 对象初始化的时候,会首先读取 req.stream()
中的数据,然后对数据进行解析。
查看 poco/Net/src/HTMLForm.cpp
源码,发现HTMLForm只能支持两种格式的数据:
- multipart/form-data
- 非multipart/form-data
const std::string HTMLForm::ENCODING_URL = "application/x-www-form-urlencoded";
const std::string HTMLForm::ENCODING_MULTIPART = "multipart/form-data";
const int HTMLForm::UNKNOWN_CONTENT_LENGTH = -1;
当 Poco 检测到 Content-Type 是 multipart/form-data 的时候,就会执行 void HTMLForm::readMultipart(std::istream& istr, PartHandler& handler)
方法,如果不是 multipart/form-data ,那么就执行 void HTMLForm::readUrl(std::istream& istr)
方法。
- HTMLForm::readMultipart() 方法会把每一个 part 作为一个 name:value 进行解析;如果遇到文件 ,就直接忽略这个文件的内容。文件可以使用自定义的
Poco::Net::PartHandler
去解析; - HTMLForm::readUrl()方法会把 content 内的所有内容作为很多 name:value 进行解析,'=‘作为name 和 value 的分隔符,’&'作为多个 name:value 之间的分隔符。获取name 和 value 后再进行 urldecode 解码。
Poco::Net::HTMLForm 的缺点就是把内容强制作为 form 进行解析,因为它根本不检查 Content-Type 是什么。
2.直接读取 req.stream()
如果接收到的数据是 json,那么最好不要使用 Poco::Net::HTMLForm
,尤其是数据中有 ‘=’ 存在的时候,Poco::Net::HTMLForm 会直接把 ‘=’ 作为分隔符使用,'=‘左边的是 name,’='右边的是 value。
那么如何读取 json 数据呢? 我们可以直接读取 req.stream()
,然后再解析json数据,就像下面这样:
void PeripheralGpsHandler::MethodPut(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response)
{
int len = request.getContentLength();
if (len < 0)
{
return;
}
istream& in = request.stream();
Poco::JSON::Parser parser;
Poco::Dynamic::Var result = parser.parse(in);
Poco::JSON::Object::Ptr pObj = result.extract<Poco::JSON::Object::Ptr>();
std::string value = pObj->getValue<std::string>("value"); //如果没有 value 字段, POCO框架会抛出一个异常, 但是程序不会崩溃
// Poco::Dynamic::Var varValue = pObj->get("value"); // 即使没有 value 字段,程序也不会崩溃,但是 varValue 的内容为空,
//可以在后面通过 if (!varValue.isEmpty()) { std::string value = varValue.convert<std::string>(); } 来判断;
//也可以在执行这一句之前,使用 if (pObject->has("value")) { }来判断该Json对象中是否含有此字段,如果含有则取出;
// // Poco::JSON::Object类 getValue 源码
// template<typename T>
// T getValue(const std::string& key) const
// {
// Dynamic::Var value = get(key);
// return value.convert<T>();
// }
/// Retrieves the property with the given name and will
/// try to convert the value to the given template type.
/// The convert<T>() method of Var is called
/// which can also throw exceptions for invalid values.
/// Note: This will not work for an array or an object.
-
服务端响应HTTP请求时,
req.stream()
函数返回的输入流就是HTTP请求的请求体内容 -
客户端发送HTTP请求时,
session.sendRequest(request);
只是将HTTP头组建到std::ostream
,并返回ostream
,我们需要通过在返回的这个ostream
中追加body来诗选 HTTP Body的内容和传输
Poco::Net::HTTPClientSession session("ip", port);
session.setTimeout(Poco::Timespan(500 * 1000)); //超时时间500ms
std::ostream& requestStream = session.sendRequest(request);
QByteArray data = ui->comboBox->currentData().value<QByteArray>();
requestStream.write(data.data(), data.size()); // 将需要发送的字节数组写入请求流中
requestStream.flush(); // 刷新请求流,确保数据被发送
- 客户端接收HTTP响应时,
session.receiveResponse(response);
是获取HTTP响应的响应体。
//接收HTTP响应
Poco::Net::HTTPResponse response;
std::istream& responseStream = session.receiveResponse(response);
// 从responseStream中读取响应数据
std::stringstream ss;
Poco::StreamCopier::copyStream(responseStream, ss);
std::string responseData = ss.str();