AngularJS POST 请求失败:Response for preflight has invalid HTTP status code 404

8 浏览
0 Comments

AngularJS POST 请求失败:Response for preflight has invalid HTTP status code 404

我知道有很多类似的问题,但是我看到的没有一个解决我的问题。我已经使用了至少3个微框架,它们都无法执行简单的POST操作,而这个操作应该将数据返回:

AngularJS客户端:

var app = angular.module('client', []);
app.config(function ($httpProvider) {
  //取消下面一行的注释也会导致GET请求失败
  //$httpProvider.defaults.headers.common['Access-Control-Allow-Headers'] = '*';
  delete $httpProvider.defaults.headers.common['X-Requested-With'];
});
app.controller('MainCtrl', function($scope, $http) {
  var baseUrl = 'http://localhost:8080/server.php'
  $scope.response = 'Response goes here';
  $scope.sendRequest = function() {
    $http({
      method: 'GET',
      url: baseUrl + '/get'
    }).then(function successCallback(response) {
      $scope.response = response.data.response;
    }, function errorCallback(response) { });
  };
  $scope.sendPost = function() {
    $http.post(baseUrl + '/post', {post: 'data from client', withCredentials: true })
    .success(function(data, status, headers, config) {
      console.log(status);
    })
    .error(function(data, status, headers, config) {
      console.log('FAILED');
    });
  }
});

SlimPHP服务器:

response()->headers->set('Access-Control-Allow-Headers', 'Content-Type');
    $app->response()->headers->set('Content-Type', 'application/json');
    $app->response()->headers->set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
    $app->response()->headers->set('Access-Control-Allow-Origin', '*');
    $array = ["response" => "Hello World!"];
    $app->get('/get', function() use($array) {
        $app = \Slim\Slim::getInstance();
        $app->response->setStatus(200);
        echo json_encode($array);
    }); 
    $app->post('/post', function() {
        $app = \Slim\Slim::getInstance();
        $allPostVars = $app->request->post();
        $dataFromClient = $allPostVars['post'];
        $app->response->setStatus(200);
        echo json_encode($dataFromClient);
    });
    $app->run();

我已经启用了CORS,GET请求可以正常工作。HTML更新为服务器发送的JSON内容。但是每次我尝试使用POST时,我都会得到一个XMLHttpRequest无法加载http://localhost:8080/server.php/post。预检请求的响应具有无效的HTTP状态码404。为什么?

编辑:如Pointy所请求的那样,以下是请求/响应的头部信息:

req/res headers

0
0 Comments

问题的原因可能是由于服务器端启用了CORS并且在服务器端启用了Access-Control-Allow-Origin : *。如果GET方法可以正常工作,但POST方法无法正常工作,那么可能是由于Content-Type和data的问题。

AngularJS使用Content-Type: application/json传输数据,但某些Web服务器(尤其是PHP)不能原生地序列化它们。对于这些服务器,我们必须将数据传输为Content-Type: x-www-form-urlencoded。

示例代码如下:

$scope.formLoginPost = function () {
    $http({
        url: url,
        method: "POST",
        data: $.param({ 'username': $scope.username, 'Password': $scope.Password }),
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
    }).then(function (response) {
        // success
        console.log('success');
        console.log("then : " + JSON.stringify(response));
    }, function (response) { // optional
        // failed
        console.log('failed');
        console.log(JSON.stringify(response));
    });
};

注意:我使用$.params来将数据序列化为Content-Type: x-www-form-urlencoded。或者您可以使用以下JavaScript函数:

function params(obj){
    var str = "";
    for (var key in obj) {
        if (str != "") {
            str += "&";
        }
        str += key + "=" + encodeURIComponent(obj[key]);
    }
    return str;
}

并使用params({ 'username': $scope.username, 'Password': $scope.Password })将其序列化为Content-Type: x-www-form-urlencoded请求,该请求仅以username=john&Password=12345的形式获取POST数据。

0
0 Comments

问题原因:

出现这个问题的原因是因为在AngularJS的POST请求中,浏览器会先发送一个预检请求(preflight request)来检查服务器是否支持该请求。预检请求使用OPTIONS方法,服务器需要正确处理该请求并返回正确的响应。

在给出的代码中,服务器在处理预检请求时没有正确设置响应头,导致预检请求返回了一个错误的响应状态码404。

解决方法:

为了解决这个问题,需要在服务器端正确设置响应头来处理预检请求。在给出的代码中,可以在allowCrossDomain函数中添加以下代码来处理OPTIONS请求:

if (req.method === "OPTIONS") {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type');
    res.sendStatus(200);
} else {
    next();
}

这样就能正确处理预检请求,并返回正确的响应状态码200。这样AngularJS的POST请求就能正常发送和接收数据了。

0
0 Comments

问题原因:该问题是由于CORS策略引起的。在进行POST请求之前,Chrome会发送一个预检OPTIONS请求,服务器在实际请求之前需要处理和确认该请求。然而,对于一个简单的服务器来说,这并不是我想要的结果。因此,通过在客户端重置headers来阻止预检请求。

解决方法:在app.config中添加以下代码,重置headers以阻止预检请求:

app.config(function ($httpProvider) {
  $httpProvider.defaults.headers.common = {};
  $httpProvider.defaults.headers.post = {};
  $httpProvider.defaults.headers.put = {};
  $httpProvider.defaults.headers.patch = {};
});

这样浏览器就会直接发送POST请求。

注意事项:这种解决方法并不适用于生产环境,应该根据需要处理预检请求。

0