http: error: Request body (from stdin or a file) and request data (key=value) cannot be mixed.
Este erro é bastante enigmático. Estou escrevendo um script de shell para interagir com uma API de descanso e estou fazendo isso:
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}"
Que produz (quando precedido de 'echo' um comando que funciona perfeitamente bem. Porém, esta versão dá o erro no assunto.
Estou sendo estúpido, ou isso é outra coisa?
FYI: O resultado do acima é o seguinte (ligeiramente higienizado)
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
Este erro ocorre quando o STDIN
do HTTPie é redirecionado e os dados também são especificados nos argumentos ao mesmo tempo:
$ echo 'data' | http POST example.org more=data # This is invalid
Não estou redirecionando STDIN. Aqui está um pouco mais de contexto no script:
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}"
(e então eu analiso o arquivo 'subnet' e faço outras coisas)
O que eu poderia estar fazendo é misturar campos de formulário com cabeçalhos http. No entanto, também não consegui fazer isso funcionar corretamente (alguma combinação de enviar os dados do formulário por meio de STDIN e cabeçalhos como parâmetros ... ou como cabeçalhos e dados de formulário por meio de STDIN ou qualquer outra coisa).
Entendo, o problema é que no contexto de loop HTTPie herda seu STDIN
(que é redirecionado).
Você deve ser capaz de contornar isso alterando o STDIN
do HTTPie de volta para a entrada do terminal ( < /dev/tty
):
cat file | while read line; do
http POST example.org a="$line" < /dev/tty
done
Uau. Isso funciona. Eu não tinha ideia de que as instruções internas de um loop de shell herdam o stdin do loop ao redor.
Obrigado pela ajuda... Não tenho certeza se teria encontrado isso sozinho.
(Agora estou curioso por que (suponho que todos os shells derivados de SH) fizeram essa escolha de design ...)
Eu acho que deveria haver uma opção para desabilitar a leitura de STDIN
que funcionaria em qualquer lugar, então estou mantendo isso aberto e marcando-o como um recurso.
Isso é muito confuso e vai contra o httpie poder trabalhar em qualquer lugar. Usar esse comando dentro de um loop bash é uma aplicação muito comum. O Httpie não deve reclamar quando a chave/valor é fornecido e recebe stdin: em vez disso, deixa a chave/valor dominar.
O Httpie não deve reclamar quando a chave/valor é fornecido e recebe stdin: em vez disso, deixa a chave/valor dominar.
Isso talvez seja intuitivo para você, mas para muitos outros o exato oposto é muito mais intuitivo. Como as ferramentas não devem tentar adivinhar, é muito melhor gerar um erro e fornecer uma escotilha de escape se você achar que sabe melhor, o que acontece.
Eu me deparei com esse problema ao usar httpie dentro de uma função passada para o GNU paralelo :
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
Graças ao comentário acima , a invocação da função paralela funciona agora. Deixando este comentário aqui para referência futura 😊
Para referência futura, agora há um argumento CLI --ignore-stdin
que pode ser usado para informar explicitamente ao HTTPie que os dados da solicitação (chave=valor) devem ser preferidos ao corpo da solicitação (de stdin).
http --ignore-stdin http://… lorem=ipsum dolor=sit
Cf. https://httpie.org/docs#redirected -input
Encontrei isso ao usar http
em um loop for. Funcionou bem localmente, mas falhou no gitlab. --ignore-stdin
resolveu.
Eu tentei redirecionar stdin para null </dev/null
, mas fez httpie se comportar de forma estranha. Por que isso? Quero dizer, não deveria haver uma maneira de fazer um comando ignorar stdin do próprio shell?
@NightMachinary você deseja usar a opção --ignore-stdin
. É assim que você diz ao HTTPie para não ler STDIN
.
$ echo 'this STDIN data is ignored' | http --ignore-stdin POST httpbin.org/post hello=world
@jakubroztocil Eu sei disso, estou dizendo que se http
não tivesse --ignore-stdin
, como poderíamos eliminar stdin indo para http
do próprio shell?
@NightMachinary você não pode eliminar STDIN
(e os outros fluxos padrão), mas pode fechá-lo:
$ echo ignored data | http httpbin.org/anything 0<&-
https://superuser.com/questions/813472/how-do-i-close-stdin-in-a-shell-script
@NightMachinary e redirecionar /dev/null
é um pouco diferente:
$ http httpbin.org/anything < /dev/null
Isso ainda invoca o HTTPie com um STDIN
aberto e redirecionado, então o HTTPie o lerá e terminará com uma string vazia, que ele usará com prazer como os dados do corpo da solicitação (o padrão é POST
), a menos que você diga para não com --ignore-stdin
.
Então é basicamente equivalente a isso:
$ echo -n | http httpbin.org/anything
Comentários muito úteis
Para referência futura, agora há um argumento CLI
--ignore-stdin
que pode ser usado para informar explicitamente ao HTTPie que os dados da solicitação (chave=valor) devem ser preferidos ao corpo da solicitação (de stdin).Cf. https://httpie.org/docs#redirected -input