Подавление ошибки 302, возвращаемой httr POST

Я использую функцию R httr POST для отправки тела jSON в API. API правильно возвращает сообщение 302: Found, но httr выходит из функции до того, как я смогу получить тело ответа (которое представляет собой тело jSON с некоторыми ключевыми битами информации).

Запустив httr с аргументом Verbose(), вы получите следующий ответ:

<- HTTP/1.1 302 Found
<- Cache-Control: no-cache
<- Pragma: no-cache
<- Content-Length: 47
<- Content-Type: application/json; charset=utf-8
<- Expires: -1
Error in function (type, msg, asError = TRUE)  : 
  necessary data rewind wasn't possible

Я запустил тот же пост cURL с терминала и могу подтвердить, что то, что я отправляю, дает ответ от API как с 302, так и с желаемым телом.

Для справки следует мой код R. (примечание: y — тело в формате jSON)

POST("https://thewebsite",authenticate("myusername","mypassword",type="basic"),
    add_headers("Content-Type" = "application/json"),
    body = y, verbose())

Любые мысли о том, как обойти ошибку и захватить содержимое сообщения 302?


person TS4    schedule 28.08.2014    source источник
comment
Любопытно... что произойдет, если вы PUT вместо POST? Не предназначено как решение - просто для устранения неполадок.   -  person Deryck    schedule 28.08.2014
comment
Попробовал PUT, и оказалось, что это не вариант с этим конкретным API. Выдает ошибку 405:Метод не разрешен.   -  person TS4    schedule 28.08.2014


Ответы (1)


Я просто потратил некоторое время на борьбу с этой проблемой. Проблема сводится к разнице в спецификации HTTP (которой в основном придерживается RCurl) и в том, что на самом деле делают браузеры.

Последовательность событий такова:

  1. Вы отправляете POST-запрос на сервер
  2. Сервер обрабатывает запрос и выдает вам перенаправление на новый URL-адрес.
  3. RCurl обрабатывает это как новый запрос, как POST, и пытается воспроизвести тело. (Браузер не пытается повторно отправить данные)
  4. Он не может повторно отправить данные, потому что базовый RCurl не сконструирован таким образом, что это возможно (поэтому curl жалуется: «необходимая перемотка данных невозможна»)

Решение простое — отключите следующие редиректы с помощью config(followlocation = 0L):

POST("https://thewebsite",
  authenticate("myusername","mypassword"),
  content_type_json(),
  config(followlocation = 0L),
  body = y, 
)

# PS with httr 0.4 you can simplify to
POST("https://thewebsite",
  authenticate("myusername","mypassword"),
  config(followlocation = 0L),
  body = x, encode = "json" 
)

Затем вам нужно будет просмотреть содержимое поля местоположения и выполнить перенаправление самостоятельно.

Для более подробного обсуждения основной проблемы см.:

person hadley    schedule 28.08.2014
comment
Возможно, config(post = TRUE) также может решить проблему при обработке запросов, но я не могу подтвердить без воспроизводимого примера. - person hadley; 28.08.2014
comment
@TS4 решает ли проблему использование post = TRUE вместо followlocation = 0L? - person hadley; 28.08.2014
comment
Ой, извините, похоже, мы написали одновременно. followlocation = 0L устранил проблему. Позвольте мне проверить конфигурацию (post = TRUE) сейчас. - person TS4; 29.08.2014
comment
(Post = TRUE) не решил проблему, он выдал ошибку, прежде чем я смог получить тело сообщения 302. Followlocation =0L сделал свое дело, еще раз спасибо за это. - person TS4; 29.08.2014
comment
@ TS4, не могли бы вы попробовать версию httr для разработчиков? devtools::install_github("hadley/httr"). Я думаю, что исправил проблему (т.е. вам не нужны дополнительные команды конфигурации) - person hadley; 29.08.2014
comment
Это работает. Установил версию для разработчиков, закомментировал (followinglocation= 0L) и смог извлечь тело сообщения 302. - person TS4; 30.08.2014
comment
Потрясающий. Рад, что наконец добрался до сути - спасибо за помощь! - person hadley; 30.08.2014