httplib
(적어도 Python 2.7 이상)의 동작은 적어도 하나의 자체를 추가하기 전에 기존 Content-Length
헤더가 있는지 확인하는 것과 같으므로 내용의 크기를 알면 우연히 추가 할 수 있습니다. 자신의 헤더 - 예를 들어 : 거기에 자동으로 일을 채우기 위해 len()
를 호출하는 그런 헤더, httplib
시도가 없으며,이 실패 할 경우는 몸이 파일 - 류의 객체 여야 가정에 os.fstat()
를 호출하면
c.request("POST", "/xpost", s, headers={"Content-Length": len(s.getvalue())})
OS 레벨의 파일 디스크립터로 그 크기를 결정한다. 파일 핸들에서 fileno()
메서드를 호출하여이 디스크립터를 얻는다. 그것을 줘. 이것은 실제 파일에서는 잘 작동하지만 StringIO
오브젝트는 실제 파일이 아니기 때문에 fileno()
메소드를 제공하지 않으며 조작은 AttributeError
과 함께 실패합니다. 이 오류는 httplib
에 의해 캐치되어 자동으로 처리되며 이는 단순히 Content-Length
을 추가하지 못합니다.
StringIO
개체를 확실히 사용하는 경우 위의 예에서 설명한 것처럼 가장 쉬운 방법은 직접 Content-Length
헤더를 추가하는 것입니다. 실제 상황에서 실제 파일을 사용할 때 테스트하는 것일 경우 이 플랫폼에서 작동하는 한 httplib
을 사용하여 헤더를 올바르게 설정할 수 있습니다. 그렇지 않은 경우 파일 이름에 항상 os.stat()
으로 전화하고 같은 방식으로 고유 헤더를 제공 할 수 있습니다. 당신이 진짜 파일과 StringIO
모두 처리하려면
당신은 항상 같은 것을 수행 할 수 있습니다
headers = {}
if not hasattr(body, "fileno"):
headers["Content-Length"] = len(body.getvalue())
을 ...하지만 난 당신이 그것을 필요로하지 않는 당신이 그 복잡성을 추가하지 않는 것이 좋습니다.
마지막으로 HTTP 레벨에는 chunked encoding을 사용하는 또 다른 옵션이 있는데 여기서는 Content-Length
헤더를 제공 할 필요가 없으며 본문 자체는 자체 설명 덩어리로 인코딩됩니다. 그러나 불행하게도 많은 클라이언트와 서버 (httplib
포함)의 HTTP 소프트웨어는 응답이이고 청취 대상이 이고은 항상 Content-Length
을 사용한다고 가정하는 경향이 있습니다. 이 가정은 요청은 일반적으로 작기 때문에 가정합니다. 물론 POST
과 PUT
으로 가정하면 물을 보유하지 않습니다. 당신이 당신의 서버가 청크 요청을 처리 할 것으로 확신 가정
, 당신은 그것을 시도 할 수 - 그렇게, 당신이 httplib
의 자동 Content-Length
을 물리 칠 수있는 StringIO
객체 (또는 fileno()
방법으로 무엇을 구축해야합니다 삽입)을 삽입하고 자신의 Transfer-Encoding
헤더에 값 chunked
을 제공하십시오.개인적으로 나는 당신이 다양한 서버로 작업 할 때 당신의 소프트웨어를 목표로한다면 이것을 추천하지 않을 것이다.
편집 : 여담으로, 당신을 인코딩 청크 사용하는 경우는 는는 Content-Length
헤더를 보내지해야한다 - 요청으로 HTTP RFC §4.4 항목 3을 참조 물론, 당신은 몸의 말을 신호 수 없습니다 응답을 수신 할 연결이 없기 때문에 연결을 닫는 것만으로도 충분합니다.
청크 요청의 빈약 한 지원의 예로서 nginx은 작년 말에 version 1.3.9의 핵심 기능에만 추가했습니다 (그 전에는 a plugin for it 이었지만).
편집 2 :
당신이 위키 백과 문서를 읽으면 당신이 그것에 좀 더 간단하게 올바른 헤더를 보내는 것보다 거기에 볼 수 있습니다 - 당신이 덩어리로 몸을 분할하고 각 하나를 보낼 수있다 작은 헤더는 16 진수의 청크 크기로 구성됩니다. 이것은 일반적으로 응답을 보낼 때 당신을 위해 행해지 겠지만 요청에 대한 지원이 좋지 않다고 언급했습니다.
다음은 본문을 청크로 변환하는 파일과 같은 객체를 둘러싼 래퍼의 예입니다. "hello world"
몸체가 너무 작아서 단 하나의 덩어리로 끝나기는하지만, 위의 예를 적용하여 사용 방법을 보여 줬습니다. 그러나 그것은 어떤 크기의 몸에도 효과가 있습니다. read()
메서드를 사용하는 모든 객체에서 작동해야합니다.이 객체는 Python file
객체와 동일한 방식으로 작동합니다. 실제로 이들 중 하나에 표준 파이썬 파일 객체를 래핑하면 httplib
은 len()
또는 fileno()
을 지원하지 않기 때문에 을 추가하는 것을 방지합니다. 아래에있는 내 예와 같이
당신은 여전히 자신을 Transfer-Encoding
헤더를 추가하는 것을 기억해야합니다
import httplib
import cStringIO
class ChunkedEncodingWrapper(object):
def __init__(self, fileobj, blocksize=8192):
self.fileobj = fileobj
self.blocksize = blocksize
self.current_chunk = ""
self.closed = False
def read(self, size=None):
ret = ""
while size is None or size >= len(self.current_chunk):
ret += self.current_chunk
if size is not None:
size -= len(self.current_chunk)
if self.closed:
self.current_chunk = ""
break
self._get_chunk()
else:
ret += self.current_chunk[:size]
self.current_chunk = self.current_chunk[size:]
return ret
def _get_chunk(self):
if not self.closed:
chunk = self.fileobj.read(self.blocksize)
if chunk:
self.current_chunk = "%x" % (len(chunk),) + "\r\n" + chunk + "\r\n"
else:
self.current_chunk = "0\r\n\r\n"
self.closed = True
s = cStringIO.StringIO("hello world")
w = ChunkedEncodingWrapper(s)
c = httplib.HTTPConnection("xxx.xxx.xxx.xxx")
c.request("POST", "/xpost", w, headers={"Transfer-Encoding": "chunked"})
감사와 같은 긴 응답 : 대한 많은,하지만, 난 여전히 청크 데이터를 전송하는 방법을 알아낼 수 없습니다 'httplib'에 의해 몸체가 unlen() 가능한 스트림이기 때문에 몸체의 길이는 사용할 수 없습니다. 나는 헤더에'Transfer-Encoding : chunked'를 추가하려하지만 여전히 chunkded body를 보내지 못한다 : ( – Coaku
'Transfer-Encoding' 헤더를 추가하는 것 이상을해야한다 - 스트림 주위에 넣을 수있는 래퍼를 작성하면'httplib'가 소비 할 수있는 형식으로 청크 인코딩 된 데이터를 방출합니다. – Cartroo