Python套接字客户端Post参数

时间:2015-02-23 09:47:30

标签: python sockets http post

Fir让我清楚我不想使用更高级别的API,我只想使用套接字编程

我编写了以下程序,使用POST请求连接到服务器。

import socket
import binascii

host = "localhost"
port = 9000
message = "POST /auth HTTP/1.1\r\n"
parameters = "userName=Ganesh&password=pass\r\n"
contentLength = "Content-Length: " + str(len(parameters))
contentType = "Content-Type: application/x-www-form-urlencoded\r\n"

finalMessage = message + contentLength + contentType + "\r\n"
finalMessage = finalMessage + parameters
finalMessage = binascii.a2b_qp(finalMessage)


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.sendall(finalMessage)

print(s.recv(1024))

我在网上查看了如何创建POST请求。

不知何故Paramters没有传递给服务器。我是否必须在请求之间添加或删除“\ r \ n”?

提前致谢, 问候, 内甚

1 个答案:

答案 0 :(得分:8)

此行finalMessage = binascii.a2b_qp(finalMessage)肯定是错误的,因此您应该完全删除该行,另一个问题是Content-Length之后没有新行丢失。在这种情况下,发送到套接字的请求是(我在这里显示CRLF个字符为\r\n,但为了清晰起见也分割了一行:

POST /auth HTTP/1.1\r\n
Content-Length: 31Content-Type: application/x-www-form-urlencoded\r\n
\r\n
userName=Ganesh&password=pass\r\n

显然,这对网络服务器没有多大意义。


但即使在添加换行符并删除a2b_qp之后,仍有问题是您 talking HTTP/1.1;请求必须具有HTTP {1.1(RFC 2616 14.23)的Host标头:

  

客户端必须在所有HTTP / 1.1请求中包含Host header 字段   消息。如果请求的URI不包含Internet主机名   对于所请求的服务,那么Host头字段必须是   给出一个空值。 HTTP / 1.1代理必须确保任何   请求消息它转发确实包含一个适当的主机头   标识代理请求的服务的字段。 所有   基于Internet的HTTP / 1.1服务器必须以400(错误请求)响应   任何缺少Host头的HTTP / 1.1请求消息的状态代码   字段。

此外,您不支持分块请求和持久连接,Keepalive或任何内容,因此您必须执行Connection: close(RFC 2616 14.10):

  

不支持持久连接的HTTP / 1.1应用程序必须   在每条消息中包含“关闭”连接选项。

因此,任何仍然会对没有HTTP/1.1标头的邮件做出正常响应的Host:服务器也会损坏。

这是您应该使用该请求发送到套接字的数据:

POST /auth HTTP/1.1\r\n
Content-Type: application/x-www-form-urlencoded\r\n
Content-Length: 29\r\n
Host: localhost:9000\r\n
Connection: close\r\n
\r\n
userName=Ganesh&password=pass

请注意,您在身体中添加\r\n(因此身体29的长度)。此外,您应该阅读响应,以找出您所获得的错误。


在Python 3上,工作代码会说:

host = "localhost"
port = 9000

headers = """\
POST /auth HTTP/1.1\r
Content-Type: {content_type}\r
Content-Length: {content_length}\r
Host: {host}\r
Connection: close\r
\r\n"""

body = 'userName=Ganesh&password=pass'                                 
body_bytes = body.encode('ascii')
header_bytes = headers.format(
    content_type="application/x-www-form-urlencoded",
    content_length=len(body_bytes),
    host=str(host) + ":" + str(port)
).encode('iso-8859-1')

payload = header_bytes + body_bytes

# ...

socket.sendall(payload)