Углеродная ошибка POST: ответ на предполетный период имеет недопустимый код состояния HTTP 404
Я знаю, что таких вопросов много, но никто из них не устранил мою проблему. Я уже использовал по крайней мере 3 микрокарта. Все они не могут выполнить простой POST, который должен вернуть данные:
Клиент 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');
});
}
});
Сервер 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();
Я включил CORS, и запросы GET работают. Html обновляет содержимое JSON, отправленное сервером. Однако я получаю
XMLHttpRequest не может загрузить http://localhost:8080/server.php/post. Ответ на предполетную дату имеет недопустимый код статуса HTTP 404
Каждый раз, когда я пытаюсь использовать POST. Почему?
EDIT: req/res по просьбе Pointy
![req/res headers]()
Ответы
Ответ 1
Хорошо, вот как я это понял.
Все это связано с политикой КОРС. Перед запросом POST Chrome делал запрос OPTIONS перед отправкой, который должен быть обработан и подтвержден сервером до фактического запроса. Теперь это действительно не то, что я хотел для такого простого сервера. Следовательно, сброс клиентской части заголовков предотвращает предполетную проверку:
app.config(function ($httpProvider) {
$httpProvider.defaults.headers.common = {};
$httpProvider.defaults.headers.post = {};
$httpProvider.defaults.headers.put = {};
$httpProvider.defaults.headers.patch = {};
});
Теперь браузер отправит POST напрямую. Надеюсь, это поможет многим людям... Моя настоящая проблема заключалась в том, что недостаточно понимал CORS.
Ссылка на замечательное объяснение: http://www.html5rocks.com/en/tutorials/cors/
Престижность этого ответа для показа мне пути.
Ответ 2
Вы включили CORS и включили Access-Control-Allow-Origin : *
на сервере. Если вы все равно работаете с GET
, а метод POST
не работает, это может быть из-за проблемы с проблемой Content-Type
и data
.
Первый AngularJS передает данные с помощью Content-Type: application/json
, который не сериализуется изначально некоторыми веб-серверами (в частности, 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
получают только данные POST в форме username=john&Password=12345
.
Ответ 3
Для приложения Node.js, в файле server.js, прежде чем регистрировать все мои собственные маршруты, я помещаю код ниже. Он устанавливает заголовки для всех ответов. Он также отлично завершает ответ, если он является предполетным вызовом "ОПЦИИ" и сразу же отправляет ответ перед полетом обратно клиенту без "следующего" (это слово?) Вниз по фактическим маршрутам бизнес-логики. Вот мой файл 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);