#ruby-on-rails #json
#ruby-on-rails #json
Вопрос:
Я пытаюсь обработать данные JSON, отправленные на контроллер Rails (3.1.0), путем доступа к данным через хэш параметров. К сожалению, Rails, похоже, не обрабатывает данные автоматически (как следует из документации и других вопросов по StackOverflow).
Контроллер выглядит как:
class Api::EventsController < ApplicationController
skip_before_filter :verify_authenticity_token
def create
unless params['event']['timestamp'].nil?
...
end
...
render :json => { :status => :success }
end
end
HTTP-запрос выглядит следующим образом (записывается с помощью tcpdump):
POST /api/locations/1/events HTTP/1.1
Date: Mon, 10 Oct 2011 21:57:22 GMT 00:00
Content-Type: application/json; charset=UTF-8
Accept: application/json
Host: 10.0.2.2:3000
User-Agent: Restlet-Framework/2.1rc1
Authorization: Basic ...
Transfer-Encoding: chunked
Connection: Keep-Alive
4e
{"event":{"data_source":"ANDROID","timestamp":1318283841768,"type":"LEAVING"}}
0
В приведенном выше примере params['event']
всегда nil
. Использование ActiveSupport::JSON.decode(request.body)
для анализа данных JSON работает, но я хотел бы автоматически сопоставить тело запроса с параметрами.
Редактировать: request.params
содержит только информацию о маршруте и request.request_parameters
полностью пуста.
Чего мне не хватает?
Ответ №1:
Вы уверены, что отправляете правильный запрос? Ссылаясь на RFC 2616, ваш последний фрагмент должен быть пустым, чтобы сообщить получателю об окончании передачи. Просто примите ваш запрос таким образом:
...
4e CRLF
{"event":{"data_source":"ANDROID","timestamp":1318283841768,"type":"LEAVING"}} CRLF
0 CRLF
CRLF
Вы также можете подумать о переключении с кодирования передачи на длину содержимого.
Передача-кодирование предназначено для потоковой передачи данных. Вы можете отправить несколько фрагментов данных, не зная заранее их размер. Вы должны отправить пустой фрагмент, чтобы объявить передачу завершенной.
Content-Length просто указывает длину данных, которые вы будете отправлять, чтобы получатель знал, когда передача достигла конца.
На всякий случай, если вы просто забыли вставить этот последний фрагмент:
Переопределено?
Вы случайно переопределили некоторые параметры, parameters, request_parameters, request? Почему бы не попробовать
-
request.params
для того же значения или -
request.request_parameters
для фактического хэша содержимого {:event => …} без дополнительной отправки
Комментарии:
1. Вы правы насчет завершающего пустого фрагмента. Он фактически отправлен (и завершается дополнительной последовательностью CRLF, поэтому запрос, похоже, в порядке), я просто изначально пропустил его, потому что он передается по проводам в отдельном пакете. Немного сложно изменить запрос, поскольку все это выполняется библиотекой Restlet, поэтому у меня нет контроля над фактическим форматом wire. Я проверю ваши замечания относительно случайно переопределенных методов позже, но я совершенно уверен, что ни один из них не применим (поскольку я вижу базовый хэш параметров, который содержит locations_id , в отладчике).
2. Я также пробовал request.params и request.request_parameters, как вы предложили, но они просто содержат информацию о маршруте или полностью пусты соответственно.
3. Что ж, заглядывая в код синтаксического анализа параметров в params_parser.rb, следующая строка наводит на размышления:
return false if request.content_length.zero?
Похоже, что фрагментированное кодирование не поддерживается…4. rack запустил поддержку блоков в 1.0.0 в 2009 году, и похоже, что ActionDispatch не нужно заботиться об этом, потому что промежуточное программное обеспечение запускается при загрузке всего запроса (поправьте меня, если я ошибаюсь). Приведенный вами код, похоже, не связан с тем, что простые запросы GET также не имеют тела запроса (и, следовательно, content_length нуль. Я проверил это)
5. Да, запросы GET не имеют тела, но сообщения имеют. Я наблюдал, как цитируемый код выполняется в отладчике, так что это определенно актуально. Однако код взят из ruby 1.9.2, так что, возможно, JRuby или 1.9.3 устранят этот пробел. Я протестирую и сообщу…