如何在PHP中使用带凭证的Curl调用API?跨域错误排查
问题背景
尝试通过PHP的Curl调用API接口,持有服务器要求的ClientId和Password,参考Swagger UI文档页面,但调用后收到服务器返回的错误信息。
错误信息
服务器返回错误:"Failed to load API definition. Errors Fetch error NetworkError when attempting to fetch resource. https://stage-sgf-partner-api.azurewebsites.net/api/swagger.json Fetch error Possible cross-origin (CORS) issue? The URL origin (https://stage-sgf-partner-api.azurewebsites.net) does not match the page (https://www.systemtest.the18club.se). Check the server returns the correct 'Access-Control-Allow-*' headers."
用户代码
$username='xxxxx'; $password='xxxxx'; $URL='https://stage-sgf-partner-api.azurewebsites.net/api/swagger/ui#/Person/PartnerApi_Person_GetGolferInfoByGolfId=114973-122'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL,$URL); curl_setopt($ch, CURLOPT_TIMEOUT, 30); //timeout after 30 seconds curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_setopt($ch, CURLOPT_USERPWD, "$username:$password"); $result=curl_exec ($ch); $status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); //get status code curl_close ($ch);
核心问题分析
- 请求URL错误:当前使用的是Swagger UI的前端页面URL(包含
#锚点),这是供人浏览的文档页面,并非实际的API接口地址。API接口的真实地址需要从Swagger文档中提取,比如/api/Person/GetGolferInfoByGolfId这类路径,再拼接域名形成完整请求地址。 - CORS错误的误导:这个CORS提示是浏览器访问Swagger UI时的跨域问题,和服务器端的PHP Curl调用完全无关——CORS是浏览器的安全限制,服务器端发起的请求不受此约束,无需关注该提示。
- 认证方式不匹配:代码中使用了HTTP基础认证(
CURLOPT_USERPWD),但如果API要求的是基于ClientId/Password的OAuth2认证(比如Client Credentials模式),这种认证方式就不适用,需要先获取令牌再调用接口。
修复方案
1. 替换为正确的API接口地址
从Swagger文档中找到GetGolferInfoByGolfId接口的真实请求路径,拼接成正确的URL,示例:
$URL = 'https://stage-sgf-partner-api.azurewebsites.net/api/Person/GetGolferInfoByGolfId?golfId=114973-122';
(注:具体路径以Swagger文档中定义的接口地址为准)
2. 调整认证方式(若API要求OAuth2)
如果API采用Client Credentials模式的OAuth2认证,需先调用令牌接口获取access_token,再携带令牌调用目标API:
$clientId = 'xxxxx'; $clientSecret = 'xxxxx'; // 第一步:获取访问令牌 $tokenUrl = 'https://stage-sgf-partner-api.azurewebsites.net/api/Token'; // 实际令牌地址以文档为准 $tokenParams = [ 'grant_type' => 'client_credentials', 'client_id' => $clientId, 'client_secret' => $clientSecret ]; $ch = curl_init($tokenUrl); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($tokenParams)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $tokenResponse = curl_exec($ch); $tokenData = json_decode($tokenResponse, true); $accessToken = $tokenData['access_token'] ?? ''; // 第二步:调用目标API $apiUrl = 'https://stage-sgf-partner-api.azurewebsites.net/api/Person/GetGolferInfoByGolfId?golfId=114973-122'; curl_setopt($ch, CURLOPT_URL, $apiUrl); curl_setopt($ch, CURLOPT_POST, false); curl_setopt($ch, CURLOPT_HTTPHEADER, [ "Authorization: Bearer $accessToken" ]); $result = curl_exec($ch); // 调试信息 if(curl_errno($ch)){ echo 'Curl错误:' . curl_error($ch); } $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch);
3. 开启调试排查
添加Curl verbose模式,输出详细请求日志,帮助定位问题:
curl_setopt($ch, CURLOPT_VERBOSE, true); // 可将日志写入文件 $verboseLog = fopen('curl_verbose.log', 'w'); curl_setopt($ch, CURLOPT_STDERR, $verboseLog);
内容的提问来源于stack exchange,提问作者Johannes

