Javascript AngularJS POST 失败:预检响应具有无效的 HTTP 状态代码 404
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33660712/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
AngularJS POST Fails: Response for preflight has invalid HTTP status code 404
提问by Deegriz
I know there are a lot of questions like this, but none I've seen have fixed my issue. I've used at least 3 microframeworks already. All of them fail at doing a simple POST, which should return the data back:
我知道有很多这样的问题,但我见过的没有一个能解决我的问题。我已经使用了至少 3 个微框架。所有这些都无法执行简单的 POST,这应该返回数据:
The angularJS client:
angularJS 客户端:
var app = angular.module('client', []);
app.config(function ($httpProvider) {
//uncommenting the following line makes GET requests fail as well
//$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');
});
}
});
The SlimPHP server:
SlimPHP 服务器:
<?php
require 'vendor/autoload.php';
$app = new \Slim\Slim();
$app->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();
I have enabled CORS, and GET requests work. The html updates with the JSON content sent by the server. However I get a
我已启用 CORS,并且 GET 请求有效。html 使用服务器发送的 JSON 内容进行更新。但是我得到了一个
XMLHttpRequest cannot load http://localhost:8080/server.php/post. Response for preflight has invalid HTTP status code 404
XMLHttpRequest 无法加载http://localhost:8080/server.php/post。预检响应具有无效的 HTTP 状态代码 404
Everytime I try to use POST. Why?
每次我尝试使用POST。为什么?
回答by Deegriz
Ok so here's how I figured this out. It all has to do with CORS policy. Before the POST request, Chrome was doing a preflight OPTIONS request, which should be handled and acknowledged by the server prior to the actual request. Now this is really not what I wanted for such a simple server. Hence, resetting the headers client side prevents the preflight:
好的,这就是我是怎么想出来的。这一切都与 CORS 政策有关。在 POST 请求之前,Chrome 正在执行预检 OPTIONS 请求,该请求应在实际请求之前由服务器处理和确认。现在这真的不是我想要的这样一个简单的服务器。因此,重置标头客户端可以防止预检:
app.config(function ($httpProvider) {
$httpProvider.defaults.headers.common = {};
$httpProvider.defaults.headers.post = {};
$httpProvider.defaults.headers.put = {};
$httpProvider.defaults.headers.patch = {};
});
The browser will now send a POST directly. Hope this helps a lot of folks out there... My real problem was not understanding CORS enough.
浏览器现在将直接发送 POST。希望这可以帮助很多人......我真正的问题是对 CORS 的了解不够。
Link to a great explanation: http://www.html5rocks.com/en/tutorials/cors/
链接到一个很好的解释:http: //www.html5rocks.com/en/tutorials/cors/
Kudos to this answerfor showing me the way.
感谢这个答案为我指明了道路。
回答by jafarbtech
You have enabled CORS and enabled Access-Control-Allow-Origin : *
in the server.If still you get GET
method working and POST
method is not working then it might be because of the problem of Content-Type
and data
problem.
您已启用 CORS 并Access-Control-Allow-Origin : *
在服务器中启用。如果您仍然使GET
方法有效但POST
方法无效,则可能是由于问题Content-Type
和data
问题。
First AngularJStransmits data using Content-Type: application/json
which is not serialized natively by some of the web servers (notably PHP). For them we have to transmit the data as Content-Type: x-www-form-urlencoded
首先,AngularJS使用Content-Type: application/json
某些 Web 服务器(特别是 PHP)未本地序列化的数据传输数据。对于他们,我们必须将数据传输为Content-Type: x-www-form-urlencoded
Example :-
例子 :-
$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));
});
};
Note :I am using $.params
to serialize the data to use Content-Type: x-www-form-urlencoded
. Alternatively you can use the following javascript function
注意:我使用$.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;
}
and use params({ 'username': $scope.username, 'Password': $scope.Password })
to serialize it as the Content-Type: x-www-form-urlencoded
requests only gets the POST data in username=john&Password=12345
form.
并用于params({ 'username': $scope.username, 'Password': $scope.Password })
序列化它,因为Content-Type: x-www-form-urlencoded
请求只获取username=john&Password=12345
表单中的 POST 数据。
回答by hoekma
For a Node.js app, in the server.js file before registering all of my own routes, I put the code below. It sets the headers for all responses. It also ends the response gracefully if it is a pre-flight "OPTIONS" call and immediately sends the pre-flight response back to the client without "nexting" (is that a word?) down through the actual business logic routes. Here is my server.js file. Relevant sections highlighted for Stackoverflow use.
对于 Node.js 应用程序,在注册我自己的所有路由之前的 server.js 文件中,我将代码放在下面。它为所有响应设置标头。如果它是飞行前“OPTIONS”调用,它也会优雅地结束响应,并立即将飞行前响应发送回客户端,而无需通过实际业务逻辑路由“下一个”(这是一个词?)。这是我的 server.js 文件。为 Stackoverflow 使用突出显示的相关部分。
// server.js
// ==================
// BASE SETUP
// import the packages we need
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var morgan = require('morgan');
var jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens
// ====================================================
// configure app to use bodyParser()
// this will let us get the data from a POST
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// Logger
app.use(morgan('dev'));
// -------------------------------------------------------------
// STACKOVERFLOW -- PAY ATTENTION TO THIS NEXT SECTION !!!!!
// -------------------------------------------------------------
//Set CORS header and intercept "OPTIONS" preflight call from AngularJS
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
if (req.method === "OPTIONS")
res.send(200);
else
next();
}
// -------------------------------------------------------------
// STACKOVERFLOW -- END OF THIS SECTION, ONE MORE SECTION BELOW
// -------------------------------------------------------------
// =================================================
// ROUTES FOR OUR API
var route1 = require("./routes/route1");
var route2 = require("./routes/route2");
var error404 = require("./routes/error404");
// ======================================================
// REGISTER OUR ROUTES with app
// -------------------------------------------------------------
// STACKOVERFLOW -- PAY ATTENTION TO THIS NEXT SECTION !!!!!
// -------------------------------------------------------------
app.use(allowCrossDomain);
// -------------------------------------------------------------
// STACKOVERFLOW -- OK THAT IS THE LAST THING.
// -------------------------------------------------------------
app.use("/api/v1/route1/", route1);
app.use("/api/v1/route2/", route2);
app.use('/', error404);
// =================
// START THE SERVER
var port = process.env.PORT || 8080; // set our port
app.listen(port);
console.log('API Active on port ' + port);