我能否使用Python的SimpleHTTPServer设置标题?

68

我正在使用 SimpleHTTPServer 来测试一些我正在开发的网页。它非常好用,但是我需要进行一些跨域请求。这需要设置一个包含页面允许访问的域名的 Access-Control-Allow-Origin 头。

有没有一种简单的方法可以在 SimpleHTTPServer 中设置头并提供原始内容呢?每个请求的头都是相同的。

4个回答

69

这是一个小技巧,因为它改变了end_headers()的行为,但我认为它比复制和粘贴整个SimpleHTTPServer.py文件略好。

我的方法是在子类中覆盖end_headers(),并在其中调用send_my_headers(), 然后调用超类的end_headers()

它不是1-2行代码,但也不到20行; 主要是样板文件。

#!/usr/bin/env python
try:
    from http import server # Python 3
except ImportError:
    import SimpleHTTPServer as server # Python 2

class MyHTTPRequestHandler(server.SimpleHTTPRequestHandler):
    def end_headers(self):
        self.send_my_headers()

        server.SimpleHTTPRequestHandler.end_headers(self)

    def send_my_headers(self):
        self.send_header("Access-Control-Allow-Origin", "*")


if __name__ == '__main__':
    server.test(HandlerClass=MyHTTPRequestHandler)

如果您正在重新定义 do_GET,请不要忘记发送头文件:def do_GET(self): self.send_head() - user474708
2
如果使用默认的do_GET(),这个解决方案是不起作用的。它不会调用end_headers。 - Koffiman

10
我认为没有简单的方法可以做到这一点,所谓简单是指“只需添加1-2行代码即可编写附加标题并保持现有功能”。因此,最好的解决方案是对SimpleHTTPRequestHandler类进行子类化,并重新实现功能,并添加新的标题。
无法简单地完成此操作的原因在于Python库中SimpleHTTPRequestHandler类的实现:http://hg.python.org/cpython/file/19c74cadea95/Lib/http/server.py#l654。请注意send_head()方法,特别是该方法末尾的几行,这些行发送响应标头。请注意调用end_headers()方法。此方法将标头与空行一起写入输出,该行表示所有标头的结束和响应正文的开始:http://docs.python.org/py3k/library/http.server.html#http.server.BaseHTTPRequestHandler.end_headers
因此,不可能对SimpleHTTPRequestHandler处理程序进行子类化,调用超类do_GET()方法,然后只添加另一个标题——因为当调用超类do_GET()方法返回时,标头的发送已经完成。必须像这样工作,因为do_GET()方法必须发送正文(所请求的文件),并且要发送正文,它必须完成发送标头。
因此,我认为你只能使用子类化SimpleHTTPRequestHandler类,将其实现与库中的代码完全相同(只需复制粘贴即可?),并在send_head()方法中的调用end_headers()方法之前添加另一个标题。
...
self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
# this below is the new header
self.send_header('Access-Control-Allow-Origin', '*')
self.end_headers()
return f
...

嗯,是的,我正在寻找一行或两行的解决方案。复制方法是下一个最好的解决方案。 - nynexman4464
那么它不应该向公众提供self.send_header()和self.end_headers() API,因为它所做的一切只会让消费者开发人员感到困惑。这些头信息确实被添加到响应体中。 - yorkw

5
# coding: utf-8
import SimpleHTTPServer
import SocketServer
PORT = 9999

def do_GET(self):
    self.send_response(200)
    self.send_header('Access-Control-Allow-Origin', 'http://example.com')           
    self.end_headers()

Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
Handler.do_GET = do_GET
httpd = SocketServer.TCPServer(("", PORT), Handler)
httpd.serve_forever()

8
我想我应该更加清楚地表达,我的意思是我仍然希望保留原始内容,但添加标题,而不仅仅只有标题。 - nynexman4464

0

虽然这是一个较旧的答案,但它是谷歌搜索结果中的第一个...

基本上就是 @iMon0 建议的...看起来正确?.. doPOST 的示例

def do_POST(self):
    self.send_response()
    self.send_header('Content-type','application/json')
    self.send_header('Access-Control-Allow-Origin','*')
    self.end_headers()
    sTest = {}
    sTest['dummyitem'] = "Just an example of JSON"
    self.wfile.write(json.dumps(sTest))

通过这样做,流程感觉正确。
1:您收到一个请求
2:您应用所需的标头和响应类型
3:您回传您想要的数据,无论是什么或如何。
上述示例对我来说运行良好,并且可以进一步扩展,它只是一个裸骨JSON post服务器。因此,我将在SOF上留下它,以防有人需要它,或者我自己在几个月后需要它。
这确实生成一个有效的JSON文件,其中仅包含sTest对象,与PHP生成的页面/文件相同。

1
我猜原问题可能需要更清晰,但我的意思是想要一种简单的方法来为开发目的从目录中提供内容,并添加一个头以允许跨域请求。我的理想情况是像 python -m SimpleHTTPServer --header=Access-Control-Allow-Origin 这样的东西。这是不可能的,所以你最终不得不实现一些代码来完成它。当然,你可以扩展 SimpleHTTPServer 来做很多其他的事情。 - nynexman4464
你应当能够从已提供的内容中发布头信息,否则 PHP 现在提供了自己的网络服务器,因此你不需要安装 apache。它允许你只需选择一个目录即可启动它,无需其他操作。只要你找到了解决方案。 - Angry 84
1
self.send_response 会导致错误。1)它是一个函数,所以实际上应该是 self.send_response();2)该函数总是需要你传递一个 code 参数的值。 - rbaleksandar
self.send_response = 打字错误。 - Angry 84

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接