发送HTTP Post Requests在Fiddler中工作,但在Python中不起作用

时间:2014-03-17 22:38:25

标签: python api http python-2.7 post

我在Fiddler2中发送了几个帖子请求来检查我的网站以确保它正常工作。但是,当我在Python中自动化以模拟这几个小时(我真的不想花7个小时来打空间!)。

这适用于提琴手。我可以创建帐户并执行相关的API命令。但是在Python中,此代码没有任何反应:

def main():
    import socket
    from time import sleep
    x = raw_input("Points: ")
    x = int(x)
    x = int(x/150)
    for y in range(x):
        new = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        new.connect(('example.com', 80))
        mydata ="""POST http://www.example.com/api/site/register/ HTTP/1.1
Host: www.example.com
Connection: keep-alive
Content-Length: 191
X-NewRelic-ID: UAIFVlNXGwEFV1hXAwY=
Origin: http://www.example.com
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
X-CSRFToken: CEC9EzYaQOGBdO9HGPVVt3Fg66SVWVXg
DNT: 1
Referer: http://www.example.com/signup
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-GB,en;q=0.8
Cookie: sessionid=sessionid; sb-closed=true; arp_scroll_position=600; csrftoken=2u92jo23g929gj2; __utma=912.1.1.2.5.; __utmb=9139i91; __utmc=2019199; __utmz=260270731.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided)

username=user&password=password&moredata=here """
        new.send(mydata.encode('hex'))
        print "Sent", y, "of", x
        sleep(1)
    print "Sent all!"
    print "restarting"
    main()
main()        

我知道我可以使用While True,但我打算稍后添加更多功能来测试更多网站。

为什么这个程序对API没有任何作用,当Fiddler2可以?我知道这是我的程序,因为我可以在fiddler中发送完全相同的数据包(显然指向正确的位置)并且它可以工作。

PS - 如果有人确实解决了这个问题,因为它可能非常明显,请你只能使用与Python捆绑在一起的模块。我无法从其他地方安装模块。谢谢!

1 个答案:

答案 0 :(得分:2)

HTTP请求并不像您想象的那么容易。首先,这是错误的:

"""POST http://www.example.com/api/site/register/ HTTP/1.1
Host: www.example.com
Connection: keep-alive
...
"""

HTTP请求中的每一行都必须以CRLF结尾(在Python中使用\r\n),即它应该是:

"""POST http://www.example.com/api/site/register/ HTTP/1.1\r
Host: www.example.com\r
Connection: keep-alive\r
...
"""

注意:LF =换行符= \n是隐含的。你也没有在你的提琴手中看到CR,因为它是一个白色空间。但它必须在那里(简单的复制粘贴不起作用)。

HTTP也指定在标题之后还必须有CRLF。即您的整个请求应该是:

    mydata = """POST http://www.example.com/api/site/register/ HTTP/1.1\r
Host: www.example.com\r
Connection: keep-alive\r
Content-Length: 191\r
X-NewRelic-ID: UAIFVlNXGwEFV1hXAwY=\r
Origin: http://www.example.com\r
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36\r
Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r
Accept: application/json, text/javascript, */*; q=0.01\r
X-Requested-With: XMLHttpRequest\r
X-CSRFToken: CEC9EzYaQOGBdO9HGPVVt3Fg66SVWVXg\r
DNT: 1\r
Referer: http://www.example.com/signup\r
Accept-Encoding: gzip,deflate,sdch\r
Accept-Language: en-GB,en;q=0.8\r
Cookie: sessionid=sessionid; sb-closed=true; arp_scroll_position=600; csrftoken=2u92jo23g929gj2; __utma=912.1.1.2.5.; __utmb=9139i91; __utmc=2019199; __utmz=260270731.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided)\r
\r
username=user&password=password&moredata=here"""

警告:它应该和我写的完全一样。每行前面不能有任何空格,即:

    mydata = """POST http://www.example.com/api/site/register/ HTTP/1.1\r
    Host: www.example.com\r
    Connection: keep-alive\r
    ...
"""

错了。

旁注:您可以将mydata移到循环外的顶部。不重要的优化,但使您的代码更清洁。

现在您已经说过您使用的网站希望您对HTTP请求进行十六进制编码?我很难相信(根据定义,HTTP是一个原始字符串)。不要这样做(并要求他们指定这个十六进制编码的确切含​​义)。可能他们意味着URL应该是十六进制编码的(因为它是HTTP中实际使用的唯一十六进制编码)?在你的情况下,没有任何编码,所以不要担心它。只需删除.encode('hex')行。

Content-Length标题也搞砸了。它应该是内容的实际长度。因此,如果正文为username=user&password=password&moredata=here,那么它应该是Content-Length: 45

接下来是服务器可能不允许您在没有得到响应的情况下发出多个请求。您应该使用new.recv(b),其中b是您要读取的字节数。但你应该阅读多少?那么这可能是有问题的,那就是Content-Length标题出现的地方。首先你需要阅读标题(即阅读直到你阅读\r\n\r\n这意味着标题的结尾),然后你必须阅读正文(基于Content-Length标题)。你可以看到事情变得混乱(见:答案的最后一部分)。

您的代码可能存在更多问题。例如,X-CSRFToken表明该站点使用CSRF预防机制。在这种情况下,您的请求可能根本不起作用(您必须从服务器获取X-CSRFToken标头的值)。

最后:不要直接使用套接字。 Httplib(http://docs.python.org/2/library/httplib.html)是一个很棒的(内置)库,用于发出HTTP请求,它将为您处理所有时髦和棘手的HTTP内容。例如,您的代码可能如下所示:

import httplib

headers = {
    "Host": "www.example.com",
    "X-NewRelic-ID": "UAIFVlNXGwEFV1hXAwY=",
    "Origin": "http://www.example.com",
    "Connection": "keep-alive",
    "User-Agent": "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36",
    "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
    "Accept": "application/json, text/javascript, */*; q=0.01",
    "X-Requested-With": "XMLHttpRequest",
    "X-CSRFToken": "CEC9EzYaQOGBdO9HGPVVt3Fg66SVWVXg",
    "DNT": "1",
    "Referer": "http://www.example.com/signup",
    "Accept-Encoding": "gzip,deflate,sdch",
    "Accept-Language": "en-GB,en;q=0.8",
    "Cookie": "sessionid=sessionid; sb-closed=true; arp_scroll_position=600; csrftoken=2u92jo23g929gj2; __utma=912.1.1.2.5.; __utmb=9139i91; __utmc=2019199; __utmz=260270731.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided)"
}

body = "username=user&password=password&moredata=here"

conn = httplib.HTTPConnection("example.com")
conn.request("POST", "http://www.example.com/api/site/register/", body, headers)
res = conn.getresponse()

请注意,您无需指定Content-Length标题。