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

如何在Asio HTTPS服务器中处理HTTP连接并返回308重定向?

解决方案

当SSL握手因HTTP请求失败时,SSL流已处于错误状态,无法继续通过它发送数据。必须直接操作底层的TCP套接字来返回308响应,之后关闭连接。

核心思路

  1. 准确识别握手失败的原因是HTTP请求(SSL_R_HTTP_REQUEST)。
  2. 获取SSL流底层的原始TCP套接字,绕过失效的SSL层。
  3. 构造符合HTTP规范的308永久重定向响应并发送。
  4. 发送完成后正确关闭套接字,释放资源。

修改后的代码示例

同步发送版本(适用于简单场景)

void HttpSession::onHandshake(boost::beast::error_code errorCode)
{
    if (!errorCode)
    {
        readHttps();
        return;
    }

    // 校验是否为HTTP请求导致的SSL握手失败
    if (errorCode.category() == boost::asio::error::get_ssl_category() &&
        ERR_GET_REASON(errorCode.value()) == SSL_R_HTTP_REQUEST)
    {
        // 获取底层TCP套接字(根据你的SSL流类型调整next_layer调用次数)
        auto& socket = ssl_stream_.next_layer().next_layer();

        // 构造308响应,替换getHost()为你获取请求主机名的逻辑
        std::string response =
            "HTTP/1.1 308 Permanent Redirect\r\n"
            "Location: https://" + getHost() + "\r\n"
            "Connection: close\r\n"
            "\r\n";

        // 同步发送响应
        boost::asio::write(socket, boost::asio::buffer(response), errorCode);

        // 关闭套接字
        socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send, errorCode);
        socket.close(errorCode);
        return;
    }

    // 处理其他握手错误
    closeSession();
}

异步发送版本(适用于异步IO模型)

如果你的服务器基于异步IO设计,避免同步阻塞,改用异步发送:

void HttpSession::send308Response()
{
    auto& socket = ssl_stream_.next_layer().next_layer();
    std::string response =
        "HTTP/1.1 308 Permanent Redirect\r\n"
        "Location: https://" + getHost() + "\r\n"
        "Connection: close\r\n"
        "\r\n";

    // 异步发送响应,绑定完成回调
    boost::asio::async_write(socket, boost::asio::buffer(response),
        std::bind(&HttpSession::onSend308Complete, shared_from_this(),
            std::placeholders::_1, std::placeholders::_2));
}

void HttpSession::onSend308Complete(boost::beast::error_code errorCode, std::size_t bytesTransferred)
{
    auto& socket = ssl_stream_.next_layer().next_layer();
    // 关闭发送端,然后关闭套接字
    socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send, errorCode);
    socket.close(errorCode);
}

void HttpSession::onHandshake(boost::beast::error_code errorCode)
{
    if (!errorCode)
    {
        readHttps();
        return;
    }

    if (errorCode.category() == boost::asio::error::get_ssl_category() &&
        ERR_GET_REASON(errorCode.value()) == SSL_R_HTTP_REQUEST)
    {
        send308Response();
        return;
    }

    closeSession();
}

关键注意事项

  • 错误码判断:用ERR_GET_REASON配合SSL类别校验,比直接ERR_PACK更可靠,避免版本差异导致的匹配失败。
  • 套接字获取:根据你的SSL流类型调整next_layer()的调用次数——如果是ssl_stream<tcp_stream>,需要两次next_layer()才能拿到tcp::socket。
  • 响应规范:必须包含Connection: close头,明确告知客户端响应发送完毕后关闭连接;Location头要填写正确的HTTPS地址。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 18:15:22