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

使用Winsock C++调用PayPal REST API获令牌遇403错误求助

用Winsock集成PayPal REST API时遇到403错误的问题排查与修复

我想在C++项目里用Winsock发送原始字符串请求集成PayPal REST API,代码基本能跑,但现在收到403错误,应该是参数配置有问题。下面是我请求访问令牌的代码:

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <string>
#include <iostream>
#include <winsock2.h>
#include <windows.h>
#include <WS2tcpip.h>

void Call_REST(
    std::string verb,
    std::string resource,
    std::vector<std::string> headers,
    std::string body,
    std::string& response)
{
    std::string req = "";
    WSADATA wsaData;
    struct hostent* host;
    SOCKADDR_IN SockAddr;

    // Init WSA
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
        Logger::ThrowBox("WSAStartup failed.");

    // Make socket
    SOCKET Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    // Find host header
    for (auto& h : headers)
        if (h.find("Host: ") != std::string::npos)
        {
            // Extract host name and port from Host header
            std::string hostname = h.substr(6, h.find_last_of(":") - 6);
            u_short port = std::stoi(h.substr(h.find_last_of(":") + 1));

            host = gethostbyname(hostname.c_str());
            SockAddr.sin_port = htons(port);
            SockAddr.sin_family = AF_INET;
            SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);

            // Connect socket
            if (connect(Socket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr)) != 0)
            {
                int error = WSAGetLastError();
                Logger::ThrowBox("Could not connect.\nError: " + std::to_string(error));
            }
            else
                OutputDebugStringA("Connected!");
        }

    // Append HTTP verb and resource
    req += verb + " " + resource + " HTTP/1.1\r\n";

    // Append all the headers
    for (auto& h : headers) req += h + "\r\n";
    req += "Content-length: " + std::to_string(body.length()) + "\r\n\r\n";

    // Append body
    req += body;

    // Send request, Receive response, close connection, shut down WSA
    send(Socket, req.c_str(), req.size(), 0);
    char buffer[1024 * 10];
    int nlen;
    while ((nlen = recv(Socket, buffer, 1024 * 10, 0)) > 0)
    {
        response.append(buffer, 0, nlen);
    }
    closesocket(Socket);
    WSACleanup();
}

int main()
{
    std::string id; // my id here
    std::string secret; // my secret here
    std::string json = "{\n\"Username\": \"" + id + "\",\n\"Password\": \""
        + secret + "\"\n\"grant_type\": \"client_credentials\"\n}";

    std::string result;
    Call_REST("POST",
        "https://api-m.sandbox.paypal.com/v1/oauth2/token",
        {
            "Host: www.sandbox.paypal.com:80",
            "Cache-Control: no-cache",
            "Content-Type: application/json",
            "Accept: application/json",
            "Accept-Language: en_US"
        },
        json,
        result);
}

问题根源与修复方案

1. HTTPS支持缺失与端口错误

PayPal的REST API仅接受HTTPS请求(443端口),但当前代码直接用普通TCP socket连接80端口(HTTP),这会直接导致请求被拒绝(403)。你需要在Winsock基础上添加SSL/TLS加密层,比如使用Windows原生的Schannel库或者第三方库如OpenSSL来建立安全连接。

同时,Host头和请求资源不匹配:

  • Host应改为api-m.sandbox.paypal.com:443,而非www.sandbox.paypal.com:80
  • 请求行里的资源只需传路径/v1/oauth2/token,不需要完整的HTTPS URL

2. 认证方式错误

PayPal获取访问令牌要求使用Basic认证,不是在JSON请求体里传递用户名密码:

  • 将你的client_id和secret用冒号拼接成id:secret格式,再做Base64编码
  • 在请求头中添加Authorization: Basic <Base64编码后的字符串>

3. 请求体格式错误

PayPal的token接口要求请求体为x-www-form-urlencoded格式,而非JSON,正确的请求体内容是grant_type=client_credentials,不需要再传递用户名密码(已通过Basic Auth完成认证)。另外你原有的JSON存在语法错误(Password字段后缺少逗号)。

4. 核心代码修正示例

以下是修正后的核心部分示例(假设已添加SSL/TLS支持):

int main()
{
    std::string id = "你的client_id";
    std::string secret = "你的secret";
    // 生成Basic Auth的Base64编码字符串
    std::string auth_str = id + ":" + secret;
    std::string base64_auth = /* 这里实现Base64编码逻辑 */;

    std::string result;
    Call_REST("POST",
        "/v1/oauth2/token",  // 仅传递路径
        {
            "Host: api-m.sandbox.paypal.com:443",
            "Cache-Control: no-cache",
            "Content-Type: application/x-www-form-urlencoded",  // 修正Content-Type
            "Accept: application/json",
            "Accept-Language: en_US",
            "Authorization: Basic " + base64_auth  // 添加Basic认证头
        },
        "grant_type=client_credentials",  // 修正请求体
        result);
}

另外,你需要补充Base64编码的实现,以及完善SSL/TLS连接的逻辑——普通TCP socket无法直接处理HTTPS流量。

内容的提问来源于stack exchange,提问作者Mikołaj Gogola

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 08:40:44