javascript - example - ng-src
AngularJS POST falla: la respuesta para la verificación previa tiene un código de estado HTTP 404 no válido (3)
Ha habilitado CORS y
Access-Control-Allow-Origin : *
en el servidor. Si todavía obtiene el método
GET
funcionando y el método
POST
no funciona, puede deberse al problema de
Content-Type
y de
data
.
Primero
AngularJS
transmite datos usando
Content-Type: application/json
que no está serializado de forma nativa por algunos de los servidores web (especialmente PHP).
Para ellos tenemos que transmitir los datos como
Content-Type: x-www-form-urlencoded
Ejemplo:
$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));
});
};
Nota:
Estoy usando
$.params
para serializar los datos para usar
Content-Type: x-www-form-urlencoded
.
Alternativamente, puede usar la siguiente función de JavaScript
function params(obj){
var str = "";
for (var key in obj) {
if (str != "") {
str += "&";
}
str += key + "=" + encodeURIComponent(obj[key]);
}
return str;
}
y use
params({ ''username'': $scope.username, ''Password'': $scope.Password })
para serializarlo como el tipo de
Content-Type: x-www-form-urlencoded
solicitudes
Content-Type: x-www-form-urlencoded
solo obtienen los datos POST en
username=john&Password=12345
formulario.
Sé que hay muchas preguntas como esta, pero ninguna que haya visto ha solucionado mi problema. Ya he usado al menos 3 microframeworks. Todos ellos fallan al hacer una POST simple, que debería devolver los datos:
El cliente 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'');
});
}
});
El servidor 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();
He habilitado CORS y las solicitudes GET funcionan. El html se actualiza con el contenido JSON enviado por el servidor. Sin embargo me sale un
XMLHttpRequest no puede cargar http://localhost:8080/server.php/post . La respuesta para la verificación previa tiene un código de estado HTTP 404 no válido
Cada vez que trato de usar POST. ¿Por qué?
Ok, así es como descubrí esto. Todo tiene que ver con la política de CORS. Antes de la solicitud POST, Chrome estaba haciendo una solicitud OPTIONS de verificación previa, que el servidor debe manejar y reconocer antes de la solicitud real. Ahora bien, esto no es lo que quería para un servidor tan simple. Por lo tanto, restablecer los encabezados del lado del cliente evita la verificación previa:
app.config(function ($httpProvider) {
$httpProvider.defaults.headers.common = {};
$httpProvider.defaults.headers.post = {};
$httpProvider.defaults.headers.put = {};
$httpProvider.defaults.headers.patch = {};
});
El navegador ahora enviará una POST directamente. Espero que esto ayude a mucha gente ... Mi verdadero problema era no entender CORS lo suficiente.
Enlace a una gran explicación: http://www.html5rocks.com/en/tutorials/cors/
Felicitaciones a esta respuesta por mostrarme el camino.
Para una aplicación Node.js, en el archivo server.js antes de registrar todas mis rutas, pongo el código a continuación. Establece los encabezados para todas las respuestas. También finaliza la respuesta con gracia si se trata de una llamada de "OPCIONES" previa al vuelo e inmediatamente envía la respuesta previa al vuelo de regreso al cliente sin "nexting" (¿es una palabra?) A través de las rutas lógicas comerciales reales. Aquí está mi archivo server.js. Secciones relevantes resaltadas para el uso de .
// 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''));
// -------------------------------------------------------------
// -- 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();
}
// -------------------------------------------------------------
// -- 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
// -------------------------------------------------------------
// -- PAY ATTENTION TO THIS NEXT SECTION !!!!!
// -------------------------------------------------------------
app.use(allowCrossDomain);
// -------------------------------------------------------------
// -- 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);