qicosmos / cinatra

modern c++(c++20), cross-platform, header-only, easy to use http framework

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

async_download 没有写入内容到文件

kiraYuukiAsuna opened this issue · comments

image
image
从result返回的结果可以看到code=206,body大小104857600,是符合预期的,但文件却是空的,没有任何内容写入到文件中,并且我看了下async_download的代码好像并没有相关写入文件的地方。

相关代码,目前我是手动写入文件的

 // Download the file in chunks of 100MB
       const size_t chunk_size = 100 * 1024 * 1024; // 100MB
       for (size_t start = 0; start < bytes_total; start += chunk_size) {
           size_t end = std::min(start + chunk_size - 1, bytes_total - 1);
           SEELE_INFO_TAG(__func__, "{}",
                          "Download Range: " + std::to_string(start) + "-" + std::to_string(end) + "/" + std::to_string
                          (bytes_total));
           std::string rangeFilePath = localSaveFilePath + "_range=" + std::to_string(start) + "-" + std::to_string(end);
           auto result = co_await client.async_download(uri, rangeFilePath, std::to_string(start) + "-" + std::to_string(end));
           if (!result.net_err && result.status == 206) {
               bytes_received += end - start + 1;

               std::ofstream ofstream(rangeFilePath, std::ios::binary);
               if(!ofstream.is_open()) {
                   SEELE_INFO_TAG(__func__, "{}", "Open File Error! File:" + rangeFilePath);
                   std::pair<ReturnWrapper, std::string> ret{
                       {
                           false, ErrorCode::AccessFileFailed,
                           "Open File Error! File:" + rangeFilePath
                       },
                       ""
                   };
                   co_return ret;
               }

               ofstream << result.resp_body;
               ofstream.close();

               rangeFiles.push_back(rangeFilePath);
           }
           else {
               SEELE_INFO_TAG(__func__, "{}", "Http Response Error!" + result.net_err.message());
               std::pair<ReturnWrapper, std::string> ret{
                   {
                       false, ErrorCode::HttpResponseError,
                       "Http Response Error!" + result.net_err.message()
                   },
                   ""
               };
               co_return ret;
           }
       }

把返回的http 头输出一下,看一下是什么格式返回的,如果是chunked或者multipart则会下载到文件,否则是直接放body里面的,如果在body里面,那你就取出来存文件吧。

另外,返回206有点奇怪,206是重定向,重定向的url在http header里面,cinatra不会自动根据重定向url去请求,需要你手动去连接新的url并发请求。

谢谢您的回复!

HTTP 206 Partial Content 成功状态响应代码表示请求已成功,并且主体包含所请求的数据区间,该数据区间是在请求的 Range 首部指定的。

如果只包含一个数据区间,那么整个响应的 Content-Type 首部的值为所请求的文件的类型,同时包含 Content-Range 首部。

如果包含多个数据区间,那么整个响应的 Content-Type 首部的值为 multipart/byteranges ,其中一个片段对应一个数据区间,并提供 Content-Range 和 Content-Type 描述信息

在我的这个例子中是只包含一个Range数据区间,响应code=206Partial Content,响应的Content-Type值为application/octet-stream,具体请求和响应的头部信息可参考下面Postman的截图:
image

所以应该是Content-Type值为application/octet-stream的时候cinatra默认不会写到文件而是会写到返回的body中吧,我以为不管什么都会写到文件的呢,这样的话那我就手动写入到文件吧,其实还更方便了,我可以控制将多次请求的文件数据片段写到一个文件里,不然默认这个async_download如果写到文件里我还需要将多次下载得到的多个文件拼接起来,不过感觉我好像不应该用这个download函数,直接用get就好了哈哈。

感谢您的回复,解答了我的疑问!

所以应该是Content-Type值为application/octet-stream的时候cinatra默认不会写到文件而是会写到返回的body中吧,我以为不管什么都会写到文件的呢,这样的话那我就手动写入到文件吧,其实还更方便了,我可以控制将多次请求的文件数据片段写到一个文件里,不然默认这个async_download如果写到文件里我还需要将多次下载得到的多个文件拼接起来,不过感觉我好像不应该用这个download函数,直接用get就好了哈哈。

感谢您的回复,解答了我的疑问!

是的,只有chunked和multipart格式才会写文件,因为这两种格式不会有content-length字段(multipart 可以有但不是http协议要求的,即使有长度可能是几个G的大文件也不适合放内存),需要流式读取到结束符为止。

另外我记错了301/302才是重定向,206是部分内容。