使用Boost.Beast实现Google Drive OAuth2设备流遇307重定向求助
解决Boost.Beast请求Google OAuth2设备流返回307重定向的问题
嘿,我之前也踩过这个坑!这个307临时重定向的问题其实很好解决——Google的OAuth2设备流接口强制要求使用HTTPS访问,而你当前的Boost.Beast代码是通过普通HTTP发送请求的,所以服务器才会把你重定向到HTTPS版本的地址。Postman默认会自动用HTTPS访问这类接口,所以它能正常拿到JSON响应。
核心问题分析
你看到的307响应里的Location字段已经给出了明确提示:它指向的是https://accounts.google.com/o/oauth2/device/code,也就是HTTPS协议的地址。你的原始代码应该是连接到了HTTP的80端口,而Google的服务器会把所有HTTP请求重定向到HTTPS的443端口。
修改后的Boost.Beast HTTPS请求代码
要解决这个问题,你需要切换到Boost.Beast的HTTPS客户端实现,用ssl::stream包装TCP流来处理SSL握手。下面是完整的示例代码:
#include <boost/beast.hpp> #include <boost/beast/ssl.hpp> #include <boost/asio/connect.hpp> #include <boost/asio/ssl/stream.hpp> #include <iostream> #include <string> namespace beast = boost::beast; namespace http = beast::http; namespace net = boost::asio; namespace ssl = net::ssl; using tcp = net::ip::tcp; int main() { try { // 初始化IO上下文 net::io_context ioc; // 创建SSL上下文,使用TLS 1.2版本 ssl::context ctx(ssl::context::tlsv12_client); // 设置默认的CA证书路径(需要系统或OpenSSL的CA证书支持) ctx.set_default_verify_paths(); // 创建带SSL的TCP流 beast::ssl_stream<beast::tcp_stream> stream(ioc, ctx); // 设置服务器主机名验证,防止中间人攻击 if(! SSL_set_tlsext_host_name(stream.native_handle(), "accounts.google.com")) { beast::error_code ec{static_cast<int>(::ERR_get_error()), net::error::get_ssl_category()}; throw beast::system_error{ec}; } // 解析服务器地址(端口443是HTTPS的默认端口) tcp::resolver resolver(ioc); auto const results = resolver.resolve("accounts.google.com", "443"); // 连接到服务器的TCP端口 beast::get_lowest_layer(stream).connect(results); // 执行SSL握手,建立HTTPS连接 stream.handshake(ssl::stream_base::client); // 构造请求(内容和你之前的一致) http::request<http::string_body> req{http::verb::post, "/o/oauth2/device/code", 11}; req.set(http::field::host, "accounts.google.com"); req.set("Cache-Control", "no-cache"); req.set(http::field::content_type, "application/x-www-form-urlencoded"); req.body() = "scope=https://www.googleapis.com/auth/drive.file&client_id=610490019085-l1v2mv7lv95lu7cr111vbtqmp1bigv42.apps.googleusercontent.com"; req.prepare_payload(); // 发送HTTPS请求 http::write(stream, req); // 接收服务器响应 beast::flat_buffer buffer; http::response<http::dynamic_body> res; http::read(stream, buffer, res); // 打印响应内容 std::cout << res << std::endl; // 关闭SSL流(忽略"未连接"的错误,因为可能服务器已经关闭连接) beast::error_code ec; stream.shutdown(ec); if(ec && ec != beast::errc::not_connected) throw beast::system_error{ec}; } catch(std::exception const& e) { std::cerr << "请求出错: " << e.what() << std::endl; return 1; } return 0; }
额外注意事项
- 链接依赖库:编译时需要链接Boost的
system、beast、asio库,以及OpenSSL的ssl和crypto库。 - 证书验证:如果你的环境中找不到默认CA证书,可能需要手动指定证书路径,或者在测试环境临时禁用验证(生产环境绝对不能这么做,会有安全风险)。
- HTTP版本:你的原始请求用的是HTTP/1.1,示例代码中保持了一致,这没问题。
这样修改后,你的Boost.Beast请求就会像Postman一样通过HTTPS发送,直接拿到预期的JSON响应,不会再触发307重定向了。
内容的提问来源于stack exchange,提问作者user2828781
相关产品推荐
相关产品推荐

