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

求助:修改PHP代理文件解决Expensify API调用的CORS问题

解决Expensify Authenticate API的CORS问题及PHP代理修复方案

我想调用Expensify的Authenticate API,但受CORS限制无法直接调用,编写了PHP代理却无法正常工作,求修改方案及参考建议。


原前端调用脚本

$(document).ready(function () {

    $("#login").click(function () {

        var partnerName = "";
        var partnerPassword = "";
        var partnerUserID = $("#email").val();
        var partnerUserSecret = $("#password").val();

        var apiResponse;
        var token;

        $.ajax({
            crossDomain: true,
            type: "POST",
            url: "https://www.expensify.com/api?command=Authenticate",
            data: {
                partnerName: partnerName,
                partnerPassword: partnerPassword,
                partnerUserID: partnerUserID,
                partnerUserSecret: partnerUserSecret
            },
            cache: false,
            success: function (data) {
                apiResponse = data;
                console.log(apiResponse);
                token = apiResponse.authToken;
                jCode = apiResponse.jsonCode;
                if (jCode == 200) {
                    window.sessionStorage
                    sessionStorage.setItem('authToken', token)
                    window.location.href = "dashboard.html";
                }
                else if (jCode == 401) {
                    alert('Wrong Password! Please enter password again')
                }
                else if (jCode == 404) {
                    alert('Email not found, enter a valid email')
                }
                else if (jCode == 407) {
                    alert('Auth Token expired, please log in again')
                }
                else if (jCode == 402) {
                    alert('Missing Information. Please fill all fields')
                }

            }

        });
    });
});

原PHP代理文件

<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST');
header("Access-Control-Allow-Headers: X-Requested-With");

$baseURL = $_REQUEST['url'];

function getRequestMethod() {
  return $_SERVER["REQUEST_METHOD"]; 
}

function getPostData() {
  return http_build_query($_POST);
}


function makeGetRequest($baseURL) {
  $ch = curl_init();
  $fullURL = $baseURL; 

  curl_setopt($ch, CURLOPT_URL, $fullURL);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

  $response = curl_exec($ch);
  curl_close($ch);
  
    if($e = curl_error($ch)) {
        echo $e;
    } else {
    $json = json_decode($response, true);
    return print_r($json);
    }
}

function makePostRequest($baseURL) {
  $ch = curl_init();
  $data = http_build_query($_POST);

  curl_setopt($ch, CURLOPT_URL, $baseURL);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

  $response = curl_exec($ch);
  curl_close($ch);

    if($e = curl_error($ch)) {
        echo $e;
    } else {
    $json = json_decode($response, true);
    return print_r($json);
    }
}

$response = "";
switch (getRequestMethod()) {
  case 'GET':
    $response = makeGetRequest($baseURL);
    break;
  case 'POST':
    $response = makePostRequest($baseURL);
    break;
  default:
    echo "There has been an error";
    return;
}

echo $response;

修复步骤

1. 前端代码修改

  • 将AJAX请求地址改为你的PHP代理文件路径(如proxy.php)
  • 添加url参数,值为Expensify的API地址
  • 指定dataType: 'json'确保前端正确解析响应
  • 增加错误处理逻辑排查问题

修改后的前端代码:

$(document).ready(function () {

    $("#login").click(function () {

        var partnerName = "";
        var partnerPassword = "";
        var partnerUserID = $("#email").val();
        var partnerUserSecret = $("#password").val();

        var apiResponse;
        var token;

        $.ajax({
            crossDomain: true,
            type: "POST",
            url: "proxy.php", // 替换为你的代理文件路径
            data: {
                url: "https://www.expensify.com/api?command=Authenticate",
                partnerName: partnerName,
                partnerPassword: partnerPassword,
                partnerUserID: partnerUserID,
                partnerUserSecret: partnerUserSecret
            },
            dataType: 'json',
            cache: false,
            success: function (data) {
                apiResponse = data;
                console.log(apiResponse);
                token = apiResponse.authToken;
                jCode = apiResponse.jsonCode;
                if (jCode == 200) {
                    sessionStorage.setItem('authToken', token)
                    window.location.href = "dashboard.html";
                }
                else if (jCode == 401) {
                    alert('Wrong Password! Please enter password again')
                }
                else if (jCode == 404) {
                    alert('Email not found, enter a valid email')
                }
                else if (jCode == 407) {
                    alert('Auth Token expired, please log in again')
                }
                else if (jCode == 402) {
                    alert('Missing Information. Please fill all fields')
                }

            },
            error: function(xhr, status, error) {
                console.error('请求错误:', error);
                alert('请求失败,请检查代理配置');
            }
        });
    });
});

2. PHP代理文件修改

  • 移除print_r,直接返回原始JSON响应,避免前端解析失败
  • 调整curl错误检查时机(需在curl_close前调用)
  • 添加JSON响应头,明确返回格式
  • 过滤url参数,避免干扰API请求数据
  • 建议生产环境开启SSL验证,提升安全性

修改后的PHP代理代码:

<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST');
header("Access-Control-Allow-Headers: X-Requested-With");
header('Content-Type: application/json');

// 检查必填的url参数
if (!isset($_REQUEST['url'])) {
    echo json_encode(['error' => 'Missing url parameter']);
    exit;
}

$baseURL = $_REQUEST['url'];
// 移除url参数,防止传递给目标API
unset($_REQUEST['url']);
unset($_POST['url']);

function getRequestMethod() {
    return $_SERVER["REQUEST_METHOD"]; 
}

function makeGetRequest($baseURL, $params) {
    $ch = curl_init();
    // 拼接GET参数
    if (!empty($params)) {
        $baseURL .= '?' . http_build_query($params);
    }

    curl_setopt($ch, CURLOPT_URL, $baseURL);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    // 生产环境请开启SSL验证
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

    $response = curl_exec($ch);
    // 在关闭curl前检查错误
    if ($e = curl_error($ch)) {
        curl_close($ch);
        echo json_encode(['error' => $e]);
        exit;
    }
    curl_close($ch);
    
    return $response;
}

function makePostRequest($baseURL, $postData) {
    $ch = curl_init();
    $data = http_build_query($postData);

    curl_setopt($ch, CURLOPT_URL, $baseURL);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    // 生产环境请开启SSL验证
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $response = curl_exec($ch);
    // 在关闭curl前检查错误
    if ($e = curl_error($ch)) {
        curl_close($ch);
        echo json_encode(['error' => $e]);
        exit;
    }
    curl_close($ch);

    return $response;
}

$response = "";
switch (getRequestMethod()) {
    case 'GET':
        $response = makeGetRequest($baseURL, $_GET);
        break;
    case 'POST':
        $response = makePostRequest($baseURL, $_POST);
        break;
    default:
        echo json_encode(['error' => 'Unsupported request method']);
        exit;
}

echo $response;

关键注意事项

  • 生产环境必须开启SSL验证,避免中间人攻击
  • 可给代理添加IP白名单或密钥验证,防止被滥用
  • 确保PHP环境已启用curl扩展(可通过phpinfo()检查)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 05:39:24