http: error: Request body (from stdin or a file) and request data (key=value) cannot be mixed.
Эта ошибка довольно загадочна. Я пишу сценарий оболочки для взаимодействия с остальным API, и я делаю это:
http --output subnet --pretty format --form post "${URLHOST}subnets" "cidr=${cidr}" "name=${name}" "description=${name}" "availabilityZoneId=${az}" "networkId=${VPCid}" "$ACCESSKEY" "$SECRETKEY" "$ACCOUNTID" "_providerId=aws" "_regionId=${REGION}"
Который выдает (когда ему предшествует «эхо» команда, которая работает отлично. Однако эта версия выдает ошибку в теме.
Я туплю или это что-то другое?
FYI: результат вышеизложенного выглядит следующим образом (слегка продезинфицирован)
http --output subnet --pretty format --form post https://test.grid.domain.com/subnets cidr=10.124.33.128/25 name=Load_balancers description=Load_balancers availabilityZoneId=us-east-1c networkId=vpc-31433e7e x-gridauth-accesskey:DOYOUNEEDTOKNOW x-gridauth-secretaccesskey:WHATISWITHALLTHEQUESTIONS x-gridauth-accountid:11223344556677 _providerId=aws _regionId=us-east-1
Эта ошибка возникает, когда HTTPie STDIN
перенаправляется, и данные также указываются в аргументах одновременно:
$ echo 'data' | http POST example.org more=data # This is invalid
Я вообще не перенаправляю STDIN. Вот еще немного контекста в сценарии:
cat keyfile | while read name az route cidr subnetid rest ; do
http --output subnet --pretty format --form post \
"${URLHOST}subnets" \
"cidr=${cidr}" \
"name=${name}" \
"description=${name}"\
"availabilityZoneId=${az}" \
"networkId=${VPCid}"\
"$ACCESSKEY" \
"$SECRETKEY"\
"$ACCOUNTID" \
"_providerId=aws" "_regionId=${REGION}"
(а затем я анализирую файл «подсети» и продолжаю делать другие вещи)
Что я МОЖЕТ делать, так это смешивать поля форм с http-заголовками. Однако я тоже не мог заставить это работать правильно (какая-то комбинация передачи данных формы через STDIN и заголовков в качестве параметров... или заголовков и данных формы через STDIN или что-то еще).
Я вижу, проблема в том, что в контексте цикла HTTPie наследует свой STDIN
(который перенаправляется).
Вы должны иметь возможность обойти это, изменив HTTPie STDIN
обратно на ввод терминала ( < /dev/tty
):
cat file | while read line; do
http POST example.org a="$line" < /dev/tty
done
Ух ты. Это работает. Я понятия не имел, что внутренние операторы цикла оболочки наследуют стандартный ввод окружающего цикла.
Спасибо за помощь... Я не уверен, что нашел бы это самостоятельно.
(Теперь мне любопытно, почему (я предполагаю, что все оболочки, производные от SH) сделали такой выбор дизайна...)
Я думаю, что должна быть возможность отключить чтение STDIN
, которая будет работать везде, поэтому я держу это открытым и помечаю как функцию.
Это очень сбивает с толку и противоречит тому, что httpie может работать где угодно. Использование такой команды внутри цикла bash — очень распространенное приложение. Httpie не должен жаловаться, когда передается ключ/значение, и он получает stdin: вместо этого позволяет доминировать ключ/значение.
Httpie не должен жаловаться, когда передается ключ/значение, и он получает stdin: вместо этого позволяет доминировать ключ/значение.
Это может быть интуитивно понятно для вас, но для многих других гораздо более интуитивно понятно прямо противоположное. Поскольку инструменты не должны пытаться угадать, гораздо лучше выдать ошибку и предоставить вам аварийный выход, если вы чувствуете, что знаете лучше, что и происходит.
Я столкнулся с этой проблемой при использовании httpie внутри функции, переданной GNU parallel :
function call_api {
local FOO=`http --json --auth $TOKEN: post $HOST/api/foo name="Ţẽṧẗ" < /dev/tty | python3 -c "import json,sys;obj=json.load(sys.stdin);print(obj['result']['id']);"`
[…]
http --download --auth $TOKEN: GET $HOST/api/bla > /dev/tty
}
export -f call_api
export HOST=…
export TOKEN=…
parallel --env HOST --env TOKEN ::: call_api call_api call_api call_api call_api
Благодаря приведенному выше комментарию вызов параллельной функции теперь работает. Оставлю этот комментарий здесь для дальнейшего использования 😊
Для справки в будущем теперь есть аргумент CLI --ignore-stdin
, который можно использовать для явного указания HTTPie, что данные запроса (ключ = значение) должны быть предпочтительнее тела запроса (из стандартного ввода).
http --ignore-stdin http://… lorem=ipsum dolor=sit
Столкнулся с этим при использовании http
в цикле for. Он отлично работал локально, но не работал в gitlab. --ignore-stdin
разрешил это.
Я попытался перенаправить stdin на null </dev/null
, но это заставило httpie вести себя странно. Почему это? Я имею в виду, не должен ли быть способ заставить команду игнорировать стандартный ввод из самой оболочки?
@NightMachinary вы хотите использовать опцию --ignore-stdin
. Вот как вы говорите HTTPie не читать STDIN
.
$ echo 'this STDIN data is ignored' | http --ignore-stdin POST httpbin.org/post hello=world
@jakubroztocil Я знаю это, я говорю, что если бы у http
не было --ignore-stdin
, как мы могли бы исключить stdin, идущий к http
из самой оболочки?
@NightMachinary вы не можете удалить STDIN
(и другие стандартные потоки), но вы можете закрыть его:
$ echo ignored data | http httpbin.org/anything 0<&-
https://superuser.com/questions/813472/how-do-i-close-stdin-in-a-shell-script
@NightMachinary и перенаправление /dev/null
немного отличаются:
$ http httpbin.org/anything < /dev/null
Это по-прежнему вызывает HTTPie с открытым и перенаправленным STDIN
, поэтому HTTPie прочитает его и получит пустую строку, которую затем с радостью использует в качестве данных тела запроса (фактически по умолчанию POST
), если только вы не скажете ему не делать это с помощью --ignore-stdin
.
Так что это в основном эквивалентно этому:
$ echo -n | http httpbin.org/anything
Самый полезный комментарий
Для справки в будущем теперь есть аргумент CLI
--ignore-stdin
, который можно использовать для явного указания HTTPie, что данные запроса (ключ = значение) должны быть предпочтительнее тела запроса (из стандартного ввода).См. https://httpie.org/docs#redirected-ввод