2015-11-11 3 views
51

Я знаю, что таких вопросов много, но я не видел, что исправил свою проблему. Я уже использовал по крайней мере 3 микрокарта. Все они не в состоянии при выполнении простой POST, который должен возвращать данные обратно:AngularJS POST Fails: ответ на предполетный период имеет неверный код состояния HTTP 404

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/Рез в соответствии с просьбой заостренными req/res headers

+0

Ну, как выглядит запрос/ответ на предполетный HTTP-запрос? – Pointy

+0

Отредактировал вопрос – Deegriz

+0

Хм, хорошо, вам не нужен явный маршрут для запроса «ОПЦИИ»? У вас есть только маршруты для «GET» и «POST». – Pointy

ответ

82

Ok так вот как я понял это. Все это связано с политикой CORS. Перед запросом 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/

Престижность this answer показал мне путь.

+33

Поскольку это дает много просмотров, я должен, вероятно, упомянуть, что это НЕ то, что вы хотите для производственное приложение. Соответственно, вы должны обрабатывать предполетный сбор. – Deegriz

+8

Это ничего не меняет ... Не понимаю, зачем и что должно делать – nclsvh

+2

Не забудьте добавить $ httpProvider.defaults.headers.get = {}; если вы выполняете запрос $ http.get(). –

2

Для приложения 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); 
6

Вы включили CORS и позволили Access-Control-Allow-Origin : * в server.If еще вы получите 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. В качестве альтернативы вы можете использовать следующую функцию яваскрипта

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 форме.

Смежные вопросы

 Смежные вопросы