【问题标题】:Requests HTTP headers请求 HTTP 标头
【发布时间】:2017-10-07 14:25:32
【问题描述】:

模块 Requests 返回的 HTTP 标头有问题。

我正在使用以下代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import requests 

response = requests.get("http://www.google.co.il",proxies={'http': '','https':''})

data = response.text 
# response.text returns the appropriate html code 
# (<!doctype html><html dir="rtl" itemscope=""....)

if response.status_code == requests.codes.ok:
    # How do I send those headers to the conn (browser)   
    print "HEADERS: " + str(response.headers) 
    conn.send(data)

我正在尝试向 www.google.co.il 发送 GET 请求,并将响应发送到浏览器(在示例中我称之为“conn”)。问题是浏览器不会显示收到的 HTML 代码,而是收到 ERR_EMPTY_RESPONSE。 响应中的标头是:

HEADERS: {'Content-Length': '5451', 'X-XSS-Protection': '1; mode=block', 'Content-Encoding': 'gzip', 'Set-Cookie': 'NID=103=RJzu4RTCNxkh-75dvKBHx-_jen9M8iPes_AdOIQqzBVZ0VPTz1PlQaAVLpwYOmxZlTKmcogiDb1VoY__Es0HqSNwlkmHl3SuBZC8_8XUfqh1PzdWTjrXRnB4S738M1lm; expires=Wed, 08-Nov-2017 10:05:46 GMT; path=/; domain=.google.co.il; HttpOnly', 'Expires': '-1', 'Server': 'gws', 'Cache-Control': 'private, max-age=0', 'Date': 'Tue, 09 May 2017 10:05:46 GMT', 'P3P': 'CP="This is not a P3P policy! See https://www.google.com/support/accounts/answer/151657?hl=en for more info."', 'Content-Type': 'text/html; charset=windows-1255', 'X-Frame-Options': 'SAMEORIGIN'}

有人告诉我问题是我没有向浏览器发送任何标题。这真的是问题吗?还有其他建议吗?如果是问题,我如何将适当的标头发送到浏览器?

编辑:我忘了提到连接是 通过代理服务器。

任何帮助都会很棒!

非常感谢,Yahli。

【问题讨论】:

  • conn 是什么?插座?
  • 是的,conn 是一个套接字。
  • 有点像拦截代理对吗?您必须向浏览器发送完整的 HTTP 响应,而不仅仅是正文。如果您使用的是 sockets ,您可以跳过 requests 并使用 socket 发送 HTTP 请求。如果您坚持使用requests,则必须从response 对象构造标题。
  • @t.m.adam 介意用这些方法写一个答案吗?因为我不知道如何使用 socket 发送 http 请求或从响应中构建标头。
  • 好的,等一下

标签: python http http-headers python-requests response


【解决方案1】:

我在 requests 文档中找不到任何关于获取原始 http 响应(不是 response.raw)的信息,所以我编写了一个函数:

def http_response(response):
    return 'HTTP/1.1 {} {}\r\n{}\r\n\r\n{}'.format(
        response.status_code, response.reason , 
        '\r\n'.join(k + ': ' + v for k, v in response.headers.items()), 
        response.content
    )

我通过将 Firefox HTTP 代理设置为 localhost:port(在端口上有一个监听套接字)对其进行了测试,它工作正常。

或者,您可以从 conn.recv 获取主机,打开一个到该主机的新套接字,然后发送数据。示例:

data = conn.recv(1024)
host = [ l.split(':')[1].strip() for l in data.splitlines() if l.startswith('Host:') ]
if len(host)  : 
    cli = socket.socket()
    cli.connect((host[0], 80))
    cli.send(data)
    response = ''
    while True : 
        data = cli.recv(1024)
        if not data.strip() : 
            break
        response += data
    conn.send(response)
    cli.close()

conn 是与网络浏览器的连接。这只是一个简单的示例,假设您只有 HTTP 请求(端口 80)。优化空间很大

【讨论】:

  • 不幸的是,当我尝试连接到“www.google.com”时,我在浏览器中收到此错误:ERR_TUNNEL_CONNECTION_FAILED(与任何其他 HTTP/s 相同)并且它不显示正确的网站。我确实收到了正确的 html 转储。任何想法为什么会发生这种情况? (我只会在 5 小时内给你投票,我已经超过了我的最大投票数,哈哈)
  • 除非我看到您的代码,否则我无法确定,但如果您正在构建一个拦截代理,这是一个 ssl 问题。 google 仅使用 HTTPS,您应该 sslwrap 您的套接字(创建证书,将其添加到受信任的机构等)。尝试在端口 80 上连接到 stackoverflow,然后告诉我会发生什么
  • 到目前为止工作不错,但如果您想处理 HTTPS,还有很多工作要做。这和requests无关,是关于服务器的,不仅仅是几行代码。
  • 基本上,您的浏览器会向您的代理发送一个 CONNECT 请求。您必须响应 200 并 sslwrap 套接字。您还需要创建证书和密钥(使用 openssl),并将该证书添加到浏览器的受信任机构。我现在不能给你链接,但你应该在 github 上找到很多例子
  • 如果您不关心拦截 HTTPS 流量或使用 requests,您可以跳过 sslwrap 和证书部分,并在循环中使用带有小超时的 select.select(如在admin_connection 脚本的功能)。如果您选择此方法,您应该设置一个标志来中断循环,例如,如果在 4 次迭代后没有收到任何内容。不过,这样会容易得多。如果您这样做是为了娱乐或研究,我建议您尝试这两种方法
猜你喜欢
  • 2015-07-13
  • 1970-01-01
  • 2019-01-08
  • 1970-01-01
  • 2012-01-06
  • 1970-01-01
  • 1970-01-01
  • 2015-08-20
  • 2016-06-29
相关资源
最近更新 更多