web-dev-qa-db-fra.com

AngularJS POST échoue: le code d'état HTTP 404 de la réponse au contrôle en amont est incorrect

Je sais qu'il y a beaucoup de questions comme celle-ci, mais aucune de celles que j'ai vues n'a résolu mon problème. J'ai déjà utilisé au moins 3 microframeworks. Tous échouent à faire un simple POST, ce qui devrait renvoyer les données:

Le 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');
    });
  }
});

Le serveur 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();

J'ai activé CORS et les requêtes GET fonctionnent. Le code HTML est mis à jour avec le contenu JSON envoyé par le serveur. Cependant je reçois un

XMLHttpRequest ne peut pas charger http: // localhost: 8080/server.php/post . La réponse au contrôle en amont a un code HTTP HTTP non valide 404

Chaque fois que j'essaie d'utiliser POST. Pourquoi?

EDIT: Les requêtes demandées par Pointy req/res headers

58
Deegriz

Ok, voici comment j'ai compris cela. Tout cela a à voir avec la politique de la SCRO. Avant la demande POST, Chrome était en train de faire une demande de contrôle en amont OPTIONS, qui devrait être gérée et reconnue par le serveur avant la demande. Maintenant, ce n’est vraiment pas ce que je voulais pour un serveur aussi simple. Par conséquent, la réinitialisation du côté client des en-têtes empêche le contrôle en amont:

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

Le navigateur va maintenant envoyer un POST directement. J'espère que cela aide beaucoup de monde… Mon vrai problème était de ne pas comprendre suffisamment la SCRO.

Lien vers une excellente explication: http://www.html5rocks.com/en/tutorials/cors/

Bravo à cette réponse pour me montrer le chemin.

84
Deegriz

Vous avez activé CORS et activé Access-Control-Allow-Origin : * sur le serveur. Si vous continuez à utiliser la méthode GET et que la méthode POST ne fonctionne pas, cela peut être dû au problème de Content-Type et data problème.

First AngularJS transmet les données en utilisant Content-Type: application/json, qui n'est pas sérialisé de manière native par certains des serveurs Web (notamment PHP). Pour eux, nous devons transmettre les données sous la forme Content-Type: x-www-form-urlencoded

Exemple: -

        $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: J'utilise $.params pour sérialiser les données afin d'utiliser Content-Type: x-www-form-urlencoded. Sinon, vous pouvez utiliser la fonction javascript suivante

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

et utilisez params({ 'username': $scope.username, 'Password': $scope.Password }) pour le sérialiser en tant que demande Content-Type: x-www-form-urlencoded ne récupère que les données POST au format username=john&Password=12345.

8
jafarbtech

Pour une application Node.js, dans le fichier server.js avant d'enregistrer tous mes propres itinéraires, je mets le code ci-dessous. Il définit les en-têtes pour toutes les réponses. Il met également fin à la réponse s'il s'agit d'un appel "OPTIONS" de pré-vol et renvoie immédiatement la réponse de pré-vol au client sans "nexting" (est-ce un mot?) Dans les routes de la logique métier proprement dite. Voici mon fichier server.js. Les sections pertinentes surlignées pour l’utilisation de 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);
3
hoekma