【问题标题】:Post Request working in Postman but returns Preflight error in Angular 2 appPost Request 在 Postman 中工作,但在 Angular 2 应用程序中返回 Preflight 错误
【发布时间】:2017-05-28 17:49:49
【问题描述】:

这是来自浏览器控制台的错误日志 XMLHttpRequest 无法加载 http://domain.com/xx/xxxxxxxx。预检响应包含无效的 HTTP 状态代码 404

这是 Postman 中收到的预期响应

{
  "status": "success",
  "code": "E012",
  "message": "Contact sent"
}

这是来自 Angular 2 的请求

makeRequest(name, recipient) {
let body = JSON.stringify({
  "name": name,
  "recipient": recipient
});

let authToken = localStorage.getItem('token');
console.log(authToken);
let headers = new Headers({'Authorization': authToken , 'Content-Type': 'application/json'}); 
let options = new RequestOptions({headers: headers});
return this.http.post(url, body, options )
  .map(res => res.json());

}

这里是 Yii2 中的行为函数

public function behaviors()
{
    $behaviors = parent::behaviors();

   // remove authentication filter
    $auth = $behaviors['authenticator'];
    unset($behaviors['authenticator']);

   // add CORS filter
    $behaviors['corsFilter'] = [
        'class' => Cors::className(),
        'cors' => [
            // restrict access to
            'Origin' => ['*'],
            'Access-Control-Request-Method' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
            // Allow only POST and PUT methods
            'Access-Control-Request-Headers' => ['*'],
            // Allow only headers 'X-Wsse'
            'Access-Control-Allow-Credentials' => true,
            // Allow OPTIONS caching
            'Access-Control-Max-Age' => 86400,
            // Allow the X-Pagination-Current-Page header to be exposed to the browser.
            'Access-Control-Expose-Headers' => [],
        ],
    ];

   // re-add authentication filter
    $behaviors['authenticator'] = $auth;
    // avoid authentication on CORS-pre-flight requests (HTTP OPTIONS method)
    $behaviors['authenticator']['except'] = ['options'];

   return $behaviors;
}

这是我的 UrlManager

   'urlManager' => [
        'enablePrettyUrl' => true,
        'enableStrictParsing' => true,
        'showScriptName' => false,
        'rules' => [
            'POST <version:[\w-]+>/sms' => '<version>/sms/send',
            'POST <version:[\w-]+>/users/verify' => '<version>/user/verify', 
            'POST <version:[\w-]+>/bulk' => '<version>/routine/index',
            'POST <version:[\w-]+>/contact' => '<version>/contact/index'],

【问题讨论】:

  • 从正文中移除 JSON.stringify
  • @Akanksha 谢谢,但这并不能解决我遇到的预检错误
  • 在 Postman 中,您选择发送 POST 请求。真正的浏览器不能那样工作。应首先发送 OPTIONS 请求以检查是否允许 POST。我想那是失败的那个。你能显示你的 php 控制器的 behaviors() 函数的内容吗?您要扩展哪个父控制器?是 ActiveController 吗?
  • 您的服务需要支持选项请求。您可以谷歌如何为您用于后端的语言和框架解析CORS
  • @SalemOuerdani 我已经编辑了我的问题以显示行为功能。我还在基础控制器中扩展了控制器类

标签: angular yii2 postman


【解决方案1】:

在某些情况下,浏览器会在实际发送卷轴之前自动执行preflight request 以检查允许的方法或动词列表。您可以在浏览器的网络选项卡中查看这些内容。我猜在 Postman 中你是直接发送 POST 请求,而预先发送的 OPTIONS 请求应该是失败的。

Yii 有一个built-in actiondefined under the ActiveController class 来响应此类请求。但是在您的情况下,您是直接扩展其父控制器,因此您需要在控制器中手动定义类似的操作(或它们的父控制器)响应预检请求:

public function actionOptions() 
{
    if (Yii::$app->getRequest()->getMethod() !== 'OPTIONS') {
        Yii::$app->getResponse()->setStatusCode(405);
    }

    $allowed_verbs = ['GET', 'POST', 'HEAD', 'OPTIONS'];
    Yii::$app->getResponse()->getHeaders()->set('Allow', implode(', ', $allowed_verbs));
}

还有;因为您没有使用built-in routing mechanism for REST;在您的情况下,您还需要手动定义 rules 到该 Options 操作:(您的 cmets 代码的编辑版本)

'urlManager' => [ 
    'enablePrettyUrl' => true,
    'enableStrictParsing' => true,
    'showScriptName' => false,
    'rules' => [ 
        'POST <version:[\w-]+>/users/verify' => '<version>/user/verify',
        'POST <version:[\w-]+>/airtime' => '<version>/airtime/airtime',
        'POST <version:[\w-]+>/bulk' => '<version>/routine/index',
        'POST <version:[\w-]+>/contact' => '<version>/contact/index',

        // OPTTIONS URI ENDPOINTS
        'OPTIONS <version:[\w-]+>/users/verify' => '<version>/user/options',
        'OPTIONS <version:[\w-]+>/airtime' => '<version>/airtime/options',
        'OPTIONS <version:[\w-]+>/bulk' => '<version>/routine/options',
        'OPTIONS <version:[\w-]+>/contact' => '<version>/contact/options',
    ],
];

【讨论】:

  • 感谢您的解释。它修复了它。
【解决方案2】:

您应该发送没有JSON.stringify 的正文:

let body = {
  "name": name,
  "recipient": recipient
};

祝你好运

【讨论】:

  • 谢谢,但这并不能解决我遇到的预检错误
  • 你确定 'url' 值是最新的吗?
  • 是的,我在邮递员中使用的 URL 与我在 Web 应用程序中使用的 URL 相同
猜你喜欢
  • 2021-04-27
  • 2021-12-26
  • 1970-01-01
  • 2012-12-31
  • 1970-01-01
  • 1970-01-01
  • 2021-07-14
  • 1970-01-01
  • 2018-03-08
相关资源
最近更新 更多