Блог веб-разработчика v 1.0.0
Symfony2, AngularJS, React, Gulp, PhpStorm и много других страшных слов

Правильная обработка POST от AngularJS в Symfony2

9 лет назад
10881 просмотр
AngularJS JavaScript PHP PHP Frameworks Symfony2

Проблема

AngularJS в отличие от большинства других фреймворков довольно нестандартно отправляет POST запросы на сервер. Если не вдаваться в технические подробности, то можно сказать, что вам просто не удастся прочитать переменную $_POST после отправки обычного POST запроса из ангуляра. По началу это пугает, потом привыкаешь.

Решение топором

POST запрос из Angular это на самом деле JSON в теле запроса. Поэтому самым простым и топорным решение будет сделать так (напоминаю, статья о Symfony2):

$data = json_decode($request->getContent(), true);

Но мы то понимаем, что это жутко неудобно, да и вообще не по фен-шую, т.к. подобные махинации придется делать в каждом экшене кажлого контроллера.

Элегантное решение

Для автоматической обработки входящих POST запросов написана удобная библиотека: https://github.com/qandidate-labs/symfony-json-request-transformer

Установить можно добавив зависимость в composer: 

"qandidate/symfony-json-request-transformer": "*"

Затем потребуется только определить специальный сервис в вашем приложении:

services:
  kernel.event_listener.json_request_transformer:
    class: Qandidate\Common\Symfony\HttpKernel\EventListener\JsonRequestTransformerListener
    tags:
      - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: 100 }

После этого можно будет читать POST из AngularJS используя привычный механизм $request->request->get('value')

На деле же происходит следующее:

  • Система проверяет, содержит ли запрос JSON
  • Если это так, то декодирует его
  • Добавляет новые значения в Request объект
  • Или возвращает HTTP 400 Bad Request если произошла ошибка при декодировании JSON

Если вы используете не Symfony

Есть чуть более громоздкое, но рабочее решение, которое не завязано на серверной стороне. Можно заставить Angular отправлять данные POST как это делают все остальные библиоеки и тем самым просто избавить себя от этой проблемы.

Для этого добавляем вызов config главного модуля следующего вида:

angular.module('myapp', [])
    .config(['$httpProvider', function($httpProvider){
        $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';

        $httpProvider.defaults.transformRequest = [function(data) {
            var param = function(obj) {
                var query = '';
                var name, value, fullSubName, subValue, innerObj, i;

                for(name in obj) {
                    value = obj[name];

                    if(value instanceof Array) {
                        for(i=0; i<value.length; ++i) {
                            subValue = value[i];
                            fullSubName = name + '[' + i + ']';
                            innerObj = {};
                            innerObj[fullSubName] = subValue;
                            query += param(innerObj) + '&';
                        }
                    } else if(value instanceof Object) {
                        for(subName in value) {
                            subValue = value[subName];
                            fullSubName = name + '[' + subName + ']';
                            innerObj = {};
                            innerObj[fullSubName] = subValue;
                            query += param(innerObj) + '&';
                        }
                    } else if(value !== undefined && value !== null) {
                        query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
                    }
                }

                return query.length ? query.substr(0, query.length - 1) : query;
            };

            return angular.isObject(data) && String(data) !== '[object File]' ? param(data) : data;
        }];
    }])
;

Честно сказать я уже и не помню где нашел этот способ, однако он работает и по сей день на последней версии ангуряла, так что можно пользоваться.

Что еще почитать
От AngularJS к React
9 лет назад
14596 просмотров
Краткий обзор фич, которые сподвигли меня использовать React в качестве JS фреймворка.