You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用asio发起HTTPS请求,响应体为不可打印Unicode字符求助

问题分析与解决

核心问题

你的代码存在两个关键问题导致响应体显示为不可打印字符:

  1. 错误操作底层TCP Socket:SSL连接建立后,所有数据交互必须通过ssl_socket对象完成,直接读取底层socket会拿到加密后的SSL数据,而非解密后的明文。你用sock.lowest_layer().available()获取的是加密字节数,并非实际明文长度,后续读取逻辑也因此出错。
  2. 响应内容被Gzip压缩:Yahoo Finance API默认返回gzip压缩的响应体,即使解密后也是二进制压缩数据,需要解压才能得到可读的JSON文本。

修复后的代码

以下是修正后的完整代码,包含gzip解压逻辑(需要链接zlib库):

#include <string>
#include <iostream>
#include <vector>
#include <sstream>
#include <zlib.h>

#include "asio.hpp"
#include "asio/ssl.hpp"

using namespace std;

// Gzip解压函数
string gzip_decompress(const vector<char>& data) {
    z_stream zs;
    memset(&zs, 0, sizeof(zs));

    if (inflateInit2(&zs, 16 + MAX_WBITS) != Z_OK) {
        throw runtime_error("inflateInit2 failed");
    }

    zs.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data.data()));
    zs.avail_in = data.size();

    int ret;
    char out_buffer[32768];
    string result;

    do {
        zs.next_out = reinterpret_cast<Bytef*>(out_buffer);
        zs.avail_out = sizeof(out_buffer);

        ret = inflate(&zs, Z_NO_FLUSH);

        if (result.size() < zs.total_out) {
            result.append(out_buffer, zs.total_out - result.size());
        }
    } while (ret == Z_OK);

    inflateEnd(&zs);

    if (ret != Z_STREAM_END) {
        throw runtime_error("gzip decompression failed: " + to_string(ret));
    }

    return result;
}

float getTickerValue(const string& ticker) {
    float tickerPrice = 0.0f;
    const string host = "query1.finance.yahoo.com";

    typedef asio::ssl::stream<asio::ip::tcp::socket> ssl_socket;

    // 创建SSL上下文
    asio::ssl::context ctx(asio::ssl::context::sslv23_client);
    ctx.set_default_verify_paths();

    asio::io_service io_service;
    ssl_socket sock(io_service, ctx);

    // 解析域名并连接
    asio::ip::tcp::resolver resolver(io_service);
    asio::ip::tcp::resolver::query query(host, "https");
    asio::connect(sock.lowest_layer(), resolver.resolve(query));
    sock.lowest_layer().set_option(asio::ip::tcp::no_delay(true));

    // SSL握手并验证证书
    sock.set_verify_mode(asio::ssl::verify_peer);
    sock.set_verify_callback(asio::ssl::rfc2818_verification(host));
    sock.handshake(ssl_socket::client);

    // 构造GET请求,添加Accept-Encoding支持gzip
    string request = "GET /v11/finance/quoteSummary/" + ticker + "?modules=financialData HTTP/1.1\r\n"
                     "Host: " + host + "\r\n"
                     "Connection: close\r\n"
                     "Accept-Encoding: gzip\r\n\r\n";

    // 发送请求
    asio::write(sock, asio::buffer(request));

    // 读取响应,分离响应头和响应体
    vector<char> buffer(4096);
    string response;
    bool header_complete = false;
    string header;
    vector<char> body;

    while (true) {
        size_t bytes_read = sock.read_some(asio::buffer(buffer));
        if (bytes_read == 0) break;

        if (!header_complete) {
            // 查找响应头结束标记\r\n\r\n
            string chunk(buffer.data(), bytes_read);
            size_t header_end = chunk.find("\r\n\r\n");
            if (header_end != string::npos) {
                header += chunk.substr(0, header_end + 4);
                body.insert(body.end(), chunk.begin() + header_end + 4, chunk.end());
                header_complete = true;
            } else {
                header += chunk;
            }
        } else {
            body.insert(body.end(), buffer.begin(), buffer.begin() + bytes_read);
        }
    }

    // 输出响应头
    cout << "响应头:\n" << header << endl;

    // 检查是否需要解压
    bool is_gzip = (header.find("Content-Encoding: gzip") != string::npos);
    string body_text;

    if (is_gzip) {
        body_text = gzip_decompress(body);
    } else {
        body_text = string(body.data(), body.size());
    }

    // 输出解压后的响应体
    cout << "\n响应体:\n" << body_text << endl;

    // 这里可以解析JSON获取tickerPrice,示例省略解析逻辑
    // 建议使用JSON库如nlohmann/json来解析

    return tickerPrice;
}

int main() {
    getTickerValue("AAPL");
    return 0;
}

关键修改说明

  1. 移除底层Socket操作:改用ssl_socket::read_some循环读取所有响应数据,直到连接关闭,确保读取的是解密后的明文。
  2. 添加Gzip解压逻辑:实现gzip_decompress函数,使用zlib库对压缩的响应体进行解压。
  3. 分离响应头与响应体:解析响应头判断是否需要解压,避免将响应头混入解压逻辑。
  4. 完善请求头:添加Accept-Encoding: gzip明确告知服务器支持压缩响应。
  5. 移除不可靠的sleep:循环读取替代休眠,确保完整获取所有响应数据。

编译说明

编译时需要链接asio和zlib库,例如GCC命令:

g++ your_code.cpp -o ticker -lasio -lz

内容的提问来源于stack exchange,提问作者soey_sause

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 02:55:21