Unix 파이프를 사용하여 REST 서비스로 데이터 스트리밍

Unix 파이프를 사용하여 REST 서비스로 데이터 스트리밍

기반으로다른 질문에 대한 답변stdout요청된 엔터티로 프로세스의 스트림을 가져오기 위해 컬을 사용하고 있습니다 POST.

myDataGeneratingApp \
| curl -H "Content-Type: application/json" -H "Transfer-Encoding: chunked" -X POST -d @- http://localhost:12000

EOF불행하게도 컬은 데이터 전송을 시작하기 전에 표준 출력을 기다리고 있습니다. 내 응용 프로그램을 독립형으로 실행할 수 있고 데이터가 즉시 콘솔에 출력되기 때문에 이를 알고 있지만, 컬링하도록 파이프하면 서비스가 데이터 수신을 시작하기 전에 눈에 띄는 지연이 발생합니다.

애플리케이션 표준에서 사용할 수 있는 경우 컬을 사용하여 데이터를 즉시 스트리밍하려면 어떻게 해야 합니까? 컬에서 불가능하다면 다른 해결책(예: wget)이 있습니까?

답변1

컬 코드 찾아보기전송.c프로그램은 청크 프로토콜을 사용하여 요청 데이터(컬에서 서버로)를 다시 패키징할 수 있는 것처럼 보입니다. 여기서 각 데이터 청크에는 ASCII 16진수 청크 길이가 앞에 붙고 \r\n.

서버에 연결되면 스트리밍을 통해 이용 가능한 것으로 보입니다 -T -. 다음 예를 고려하십시오.

for i in $(seq 5)
do date
   sleep 1
done | 
dd conv=block cbs=512 |
strace -t -e sendto,read -o /tmp/e \
 curl --trace-ascii - \
 -H "Transfer-Encoding: chunked" \
 -H "Content-Type: application/json" \
 -X POST -T -  http://localhost/...

이 스크립트는 5개의 데이터 청크를 파이프로 보냅니다. 각 청크는 날짜로 시작하고 dd512바이트로 채워져 strace파이프 curl -T -를 읽습니다. 터미널에서 우리는 볼 수 있습니다

== Info: Connected to localhost (::1) port 80 (#0)
=> Send header, 169 bytes (0xa9)
0000: POST /... HTTP/1.1
001e: Host: localhost
002f: User-Agent: curl/7.47.1
0048: Accept: */*
0055: Transfer-Encoding: chunked
0071: Content-Type: application/json
0091: Expect: 100-continue
00a7: 
<= Recv header, 23 bytes (0x17)
0000: HTTP/1.1 100 Continue

전송된 연결과 헤더를 보여줍니다. 특히 , 헤더가 curl제공 되지 않고 서버(아파치)가 응답한 헤더가 제공됩니다 . 그 뒤에는 데이터의 처음 512바이트(16진수 200)가 옵니다.Content-length:Expect:Continue

=> Send data, 519 bytes (0x207)
0000: 200
0005: Fri Sep 14 15:58:15 CEST 2018                                   
0045:                                                                 
0085:                                                                 
00c5:                                                                 
0105:                                                                 
0145:                                                                 
0185:                                                                 
01c5:                                                                 
=> Send data, 519 bytes (0x207)

출력 파일에는 strace파이프라인의 각 타임스탬프가 표시되고 연결에 기록됩니다.readsendto

16:00:00 read(0, "Fri Sep 14 16:00:00 CEST 2018   "..., 16372) = 512
16:00:00 sendto(3, "200\r\nFri Sep 14 16:00:00 CEST 20"..., 519, ...) = 519
16:00:00 read(0, "Fri Sep 14 16:00:01 CEST 2018   "..., 16372) = 512
16:00:01 sendto(3, "200\r\nFri Sep 14 16:00:01 CEST 20"..., 519, ...) = 519
16:00:01 read(0, "Fri Sep 14 16:00:02 CEST 2018   "..., 16372) = 512
16:00:02 sendto(3, "200\r\nFri Sep 14 16:00:02 CEST 20"..., 519, ...) = 519
16:00:02 read(0, "Fri Sep 14 16:00:03 CEST 2018   "..., 16372) = 512
16:00:03 sendto(3, "200\r\nFri Sep 14 16:00:03 CEST 20"..., 519, ...) = 519
16:00:03 read(0, "Fri Sep 14 16:00:04 CEST 2018   "..., 16372) = 512
16:00:04 sendto(3, "200\r\nFri Sep 14 16:00:04 CEST 20"..., 519, ...) = 519
16:00:04 read(0, "", 16372)             = 0
16:00:05 sendto(3, "0\r\n\r\n", 5, ...) = 5

보시다시피, 둘 사이의 간격은 1초로, 데이터가 수신되는 동시에 전송되고 있음을 나타냅니다. 데이터를 읽는 중이므로 전송하려면 최소한 512바이트가 있어야 합니다 fread().

답변2

아래 편집 내용을 참조하세요

당신이 원하는 것은 불가능합니다. POST 데이터를 보내려면 길이를 알아야 하므로 curl먼저 전체 데이터를 읽어서 길이를 파악해야 합니다.

Transfer-Encoding: chunked이 제한을 우회하는 방법이지만 서버의 응답에만 해당됩니다.

그 이유는 chunkedHTTP/1.1에서만 지원되는데, 요청을 보낼 때 클라이언트는 서버가 HTTP/1.1을 이해하는지 알 수 없기 때문입니다. 답변과 함께 메시지가 왔지만 요청을 보내기에는 너무 늦었습니다.

편집하다

wget 매뉴얼에 따르면 이는 wget의 제한사항인 것 같습니다.

Wget은 POST 데이터의 크기를 미리 알아야 합니다. 따라서 --post-file에 대한 인수는 일반 파일이어야 합니다. FIFO 또는 /dev/stdin과 같은 항목을 지정하면 작동하지 않습니다. HTTP/1.0에 내재된 제한 사항을 해결하는 방법은 아직 명확하지 않습니다. HTTP/1.1에서는 요청 길이를 미리 알 필요가 없는 청크 전송을 도입했지만 클라이언트는 HTTP/1.1 서버와 통신하고 있다는 사실을 알지 못하면 청크를 사용할 수 없습니다. 응답을 받을 때까지 이를 알 수 있는 방법이 없으며, 응답을 받으려면 요청이 완료되어야 합니다. 이는 닭고기와 달걀 문제입니다.

문제가 존재하지만 인식됩니다.RFC 7230:

클라이언트는 서버가 HTTP/1.1(또는 그 이상) 요청을 처리할 것이라는 사실을 알지 않는 한 전송 인코딩을 포함하는 요청을 보내면 안 됩니다. 이러한 지식은 특정 사용자 구성의 형태이거나 이전에 수신된 응답의 버전을 기억함으로써 가능합니다. .

따라서 청크된 POST 데이터를 보내는 것이 가능하며 다른 답변에서 볼 수 있듯이 컬은 이미 이를 지원합니다.

관련 정보