我在 C++ 项目中使用curl 将文件上传到服务。由于我们使用内部公司框架类来读取文件,因此我们为此定义了 READFUNCTION。内部函数可能会抛出异常,所以我想捕获它。
我的第一个想法是放置一个 try-catch
curl_easy_perform
,但我不确定这是否有效。
相反,我阅读了curl如何处理错误,并找到了ERRORBUFFER。但如何访问它?
// inside some other function
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, (char*) curlErrorBuffer);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_file);
// the READFUNCTION
size_t read_data_from_file(char* buffer, size_t size, size_t nitems, File* file) {
size_t nread = 0;
try {
nread = file->read(buffer, size * nitems);
}
catch (ReadError &e) {
nread = CURL_READFUNC_ABORT;
// How to write to ERRORBUFFER?
// strncpy(ERRORBUFFER, "Failed to read file, " + e.msg, BUF_SIZE);
}
return nread;
}
有没有办法在不将其设为全局的情况下访问 ERROBUFFER?在
curl_easy_perform
周围使用 try-catch 也可以吗?
在处理 libcurl 及其与使用异常的系统(例如 C++ 框架)的集成时,需要牢记一些注意事项。
使用 Try-Catch 周围
curl_easy_perform
在
curl_easy_perform()
周围放置一个 try-catch 块确实会捕获从 read 函数抛出的异常,假设你的库通过外部 C 风格的回调传播异常(这不是典型的或简单的)。如果您的 read 函数抛出一个未在函数本身内处理的异常,并且您的设置允许异常从 C 风格的回调中传播,那么它可以被这样的 try-catch 捕获。然而,这通常是不安全或不推荐的,因为像 libcurl 这样的 C 库并不是设计来通过回调处理异常的,如果库不支持异常,这样做可能会导致资源泄漏或未定义的行为。
访问错误缓冲区
关于
ERRORBUFFER
,libcurl 使用此缓冲区来存储其操作期间发生的错误消息。使用方法如下:
分配缓冲区:分配curl将用于存储错误消息的缓冲区。
char curlErrorBuffer[CURL_ERROR_SIZE];
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curlErrorBuffer);
```
设置选项:在调用
curl_easy_perform
之前,设置CURLOPT_ERRORBUFFER
指向该缓冲区。
失败后检查:如果
curl_easy_perform
返回错误,您可以检查curlErrorBuffer
以获取描述性错误消息。
关于在读取函数中设置错误消息,不幸的是,您无法直接写入
ERRORBUFFER
,因为它无法在 READFUNCTION
等回调函数中访问。相反,回调必须通过适当的返回代码(CURL_READFUNC_ABORT
、CURL_READFUNC_PAUSE
等)传达失败信息。
最佳实践
稳健地处理错误:
在回调中设置返回代码:使用
CURL_READFUNC_ABORT
或类似功能从读取函数发出错误情况信号。
使用附加状态:如果您需要传回详细的错误消息,您可以考虑设置一个附加状态对象,通过
CURLOPT_READDATA
选项传递给读取函数。此状态对象可以存储详细的错误消息或代码,您可以在 curl_easy_perform
完成后检查这些消息或代码。
```cpp
struct TransferState {
char* errorBuffer; // Custom error buffer for storing messages
File* file;
};
TransferState state = {curlErrorBuffer, &file};
curl_easy_setopt(curl, CURLOPT_READDATA, &state);
```
Then in your callback:
```cpp
size_t read_data_from_file(char* buffer, size_t size, size_t nitems, TransferState* state) {
try {
return state->file->read(buffer, size * nitems);
}
catch (ReadError &e) {
strncpy(state->errorBuffer, "Failed to read file", CURL_ERROR_SIZE);
return CURL_READFUNC_ABORT;
}
}
```
此设置保持干净的错误处理,而不会跨 C 和 C++ 库的边界混合异常处理,从而更严格地遵循安全和可预测的编程实践。