Angular $http发送OPTIONS而不是PUT/POST

62

我正在尝试通过PHP后端更新/插入MySQL数据库中的数据。 我正在使用AngularJS构建前端,并使用$http服务与REST API通信。

我的设置如下:

我通过$httpProvider设置标题:

 $httpProvider.defaults.withCredentials = true;
 $httpProvider.defaults.headers = {'Content-Type': 'application/json;charset=utf-8'};

而 POST 调用看起来像这样:

   return $http({
      url: url,
      method: "POST",
      data: campaign
    });

Chrome的Dev Console显示:

enter image description here

当我从POST改为PUT时,我会发送一个OPTIONS调用而不是PUT。并且内容类型切换到 content-type

我的请求有效载荷被发送为一个对象:

enter image description here

我应该如何正确设置我的头部?


编辑:

PHP后端设置了一些头部:

   $e->getResponse()
              ->getHeaders()
              ->addHeaderLine('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');

   $e->getResponse()
              ->getHeaders()
              ->addHeaderLine('Access-Control-Allow-Origin', '*');

有什么遗漏吗?


application/json 是默认的内容类型。您需要在代码中搜索一下,是否有任何地方将其设置为 text/plain。 - Chandermani
@Chandermani 我的代码相当简短。我只有一个api.js文件,在其中进行操作,还有一个.config.js文件,在其中手动设置头部。 - ohboy21
我同意一致的看法。你不应该需要你的头文件。有些非常奇怪的事情正在发生。我查看了我在Angular中编写的每个http.post,它们都是简单的。头部被假定了。 - Dave Alperovich
2个回答

72

好的,我已经解决了。

问题是什么?
DELETE、PUT和POST的CORS工作流程如下:

enter image description here

它所做的是:

  1. 检查将要进行哪个请求
  2. 如果是POST、PUT或DELETE,则先发送一个选项请求以检查发送请求的域是否与服务器的域相同
  3. 如果不相同,则需要允许访问标头才能发送此请求

这里很重要:OPTIONS请求不发送凭据。

所以我的后端服务器拒绝了PUT请求。

解决方案:
将这个放进.htaccess文件中。

RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ blank.php [QSA,L]
Header set Access-Control-Allow-Origin "http://sub.domain:3000"
Header always set Access-Control-Allow-Credentials "true"
Header always set Access-Control-Max-Age "1000"
Header always set Access-Control-Allow-Headers "X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"

完成后,在公共文件夹中创建一个名为 blank.php 的空 .php 文件。

修改:如一位评论者所指出的,您可以将这个重写规则添加到您的 .htaccess 文件中,而不是创建一个空的 PHP 文件:

RewriteRule ^(.*)$ $1 [R=200,L,E=HTTP_ORIGIN:%{HTTP:ORIGIN}]]

澄清一下:

  1. 我已经发送了Access-Control-Header
  2. 它解决的是前两行,以及
  3. 允许特定子域名和端口的Access-Control-Allow-Origin

这是我能找到的最好的网站,可以了解更多CORS信息


我们可以使用以下代码替代创建 blank.php: RewriteRule ^(.*)$ $1 [R=200,L,E=HTTP_ORIGIN:%{HTTP:ORIGIN}]] - rajagopalx
1
谢谢@gruberb。你的信息帮助我理解为什么我得到了OPTION而不是POST。 - Velidan
恭喜。我从未见过如此完整的 CORS 解释。 - Juan Rivillas
通常情况下,它不仅限于Angular。 - manish kumar
或者您可以将header(“Access-Control-Allow-Headers:X-Requested-With,Content-Type,Origin,Authorization,Accept,Client-Security-Token,Accept-Encoding”)添加到您的PHP脚本中- https://www.youtube.com/watch?v=GJAe8cZmMAs - Ryan Arief

4

您无需手动指定$http头部信息,系统已经在后台为您完成,并自动设置为application/json用于POSTPUT类型的请求。因此,您只需要

$http.post(url, data);
$http.put(url, data);

2
我将其删除,但随后我发送了一个OPTIONS调用而不是PUT / POST。如果我设置它们,至少我会发送正确的调用。 - ohboy21
1
@gruberb,你应该阅读一下这篇文章:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS - Philipp Andreychev
DELETE方法默认的content-type是text/plain。 - ecarrizo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接