使用 CURLOPT_HTTPHEADER 设置 CURL 标头会产生 CORS 问题

Posted

技术标签:

【中文标题】使用 CURLOPT_HTTPHEADER 设置 CURL 标头会产生 CORS 问题【英文标题】:Setting CURL headers using CURLOPT_HTTPHEADER creates CORS problem 【发布时间】:2019-05-23 16:08:25 【问题描述】:

我正在尝试使用 php 进行定义 HTTP 标头的 cURL POST 请求,但遇到了 CORS 问题。

所以我有一个使用 AJAX 从 webapp 调用的 .php 文件。在这个 .php 文件中,我使用 cURL 向外部 API 发出 HTTP POST 请求。在我不得不为身份验证设置不同的 HTTP 标头之前,一切都很好。当我尝试使用以下方法在 cURL 请求中定义 HTTP 标头时:

//Set Headers
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
  'Authorization': 'someAuthorization',
  'x-api-key': 'somekey',
  'Content-Type': 'application/x-www-form-urlencoded'
));

我开始在客户端(webapp)和我自己的端点之间遇到 CORS 问题,这在以前没有发生过。执行 cURL 请求后,我尝试再次定义标头,但没有成功:

//execute post
$result = curl_exec($ch);
if($result === false)
  echo 'Curl error: ' . curl_error($ch);
else
//$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
//CORS
if (isset($_SERVER['HTTP_ORIGIN'])) 
    //header("Access-Control-Allow-Origin: $_SERVER['HTTP_ORIGIN']");
    header("Access-Control-Allow-Origin: http://localhost:4200");
    header('Access-Control-Allow-Credentials: true');    
    header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); 
   
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') 
    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
        header("Access-Control-Allow-Methods: GET, POST, OPTIONS");         
    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
        header("Access-Control-Allow-Headers: 
$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']");
    exit(0);

echo $result;
;

任何想法为什么会发生这种情况?在我看来,通过执行 cURL 请求,我用 cURL 覆盖了标头,因此永远不会应用 CORS 标头配置。

这是 .php 文件中的所有代码

<?php

$url = 'someurl';
$fields = ['pax' => '2', 'ownerid' => '1', 'channel' => '3'];

//url-ify the data for the POST
$fields_string = http_build_query($fields);

//open connection
$ch = curl_init();

//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, count($fields));
curl_setopt($ch,CURLOPT_POSTFIELDS, $fields_string);

//So that curl_exec returns the contents of the cURL; rather than echoing it
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true); 

//Set Headers
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Authorization': 'someAuth',
'x-api-key': 'someKey',
'Content-Type': 'application/x-www-form-urlencoded',
));

//DISABLE SSL
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

//execute post
$result = curl_exec($ch);
if($result === false)
  echo 'Curl error: ' . curl_error($ch);
else
  //$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  //CORS
  if (isset($_SERVER['HTTP_ORIGIN'])) 
    //header("Access-Control-Allow-Origin: $_SERVER['HTTP_ORIGIN']");
    header("Access-Control-Allow-Origin: http://localhost:4200");
    header('Access-Control-Allow-Credentials: true');    
    header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); 
     
  if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') 
    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
        header("Access-Control-Allow-Methods: GET, POST, OPTIONS");         
    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
        header("Access-Control-Allow-Headers:$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']");
    exit(0);
  
  echo $result;
;

curl_close($ch);
?>

【问题讨论】:

【参考方案1】:

在 curl 请求中设置一些标头不会更改 .php 脚本中的标头。

更新 1:

您的 php 脚本中存在解析错误(您自己发现):

curl_setopt($ch, CURLOPT_HTTPHEADER, array(
  'Authorization': 'someAuthorization',
  'x-api-key': 'somekey',
  'Content-Type': 'application/x-www-form-urlencoded'
));

应该是:

curl_setopt($ch, CURLOPT_HTTPHEADER, array(
  'Authorization: someAuthorization',
  'x-api-key: somekey',
  'Content-Type: application/x-www-form-urlencoded'
));

对该脚本的 ajax 调用会导致错误 500 响应,该响应具有默认标头和 NOT 您尝试在 .php 脚本中设置的标头。

在您的本地环境中启用错误报告以“更早”地查看问题。

例如在 php.ini 中:

error_reporting=E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED 
display_errors=On

@见How do I get PHP errors to display?

【讨论】:

我已经尝试过了,但没有成功。实际上一开始就是这样,我只是把它移了下来,因为我认为 cURL 是问题所在。但仍然收到 CORS 错误:“从源 'localhost:4200' 访问 XMLHttpRequest 在 'localhost/booking/makeTempBooking.php' 已被 CORS 策略阻止:请求的资源上不存在 'Access-Control-Allow-Origin' 标头。” 只是为了测试,你可以尝试设置 * 允许所有。 header("访问控制允许来源:*");您还可以在浏览器调试控制台(网络)中检查您的请求返回的标头。 (铬:***.com/questions/4423061/…) 是的,我已经这样做了,这真的很奇怪,因为响应标头中没有“Access-Control-Allow-Origin-*”标头:Connection: Keep-Alive Content-Length: 416 Content-Type: text/html; charset=UTF-8 Date: Mon, 24 Dec 2018 18:38:09 GMT Keep-Alive: timeout=5, max=100 Server: Apache/2.4.33 (Win64) OpenSSL/1.1.0g PHP/7.2.4 X-Powered-By: PHP/7.2.4 也许它被 apache 删除了? .htaccess 还是 apache httpd.conf / extras/*.conf? 嗯,也许 curl 的返回还包含标题(标题+正文)。 $result = curl_exec($ch);您稍后使用 echo $result 。我认为有一些选项可以从响应中删除标头 curl_setopt($ch, CURLOPT_HEADER, 0); @见***.com/questions/5142869/…

以上是关于使用 CURLOPT_HTTPHEADER 设置 CURL 标头会产生 CORS 问题的主要内容,如果未能解决你的问题,请参考以下文章

php curl中CURLOPT_HTTPHEADER 这个参数的含义

curlopt_httpheader相当于c#

404 curl_error当我在CURLOPT_HTTPHEADER中添加PayPal-Mock-Response时

PHP中curl的使用

PHP中使用CURL

php curl host 设置访问指定主机