返回响应代码 Python HTTP头部
我有一个用Python搭建的服务器,它可以运行CGI脚本。
我想在我的响应中添加状态码,我已经做了这件事。
try:
cgi = CGI()
output = cgi.fire()
print 'Content-Type text/json'
print 'Status:200 success'
print
print json.dumps(output)
except:
print 'Content-Type: text/json'
print 'Status: 403 Forbidden'
print
print json.dumps({'msg':'error'})
但是当我通过dojo的xhr请求来请求这个脚本时,我却收到了200的请求状态。这是为什么呢?
头部信息
Request URL:http://192.168.2.72:8080/cgi-bin/cgi.py
Request Method:POST
Status Code:200 Script output follows
Request Headersview source
Accept:*/*
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache
Connection:keep-alive
Content-Length:125
Content-Type:application/x-www-form-urlencoded
Host:192.168.2.72:7999
Origin:http://192.168.2.72:7999
Pragma:no-cache
Referer:http://192.168.2.72:7999/home.html
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Ubuntu Chromium/25.0.1364.160 Chrome/25.0.1364.160 Safari/537.22
X-Requested-With:XMLHttpRequest
Form Dataview sourceview URL encoded
Response Headersview source
Content-Type:text/json
Date:Fri, 08 Aug 2014 05:16:29 GMT
Server:SimpleHTTP/0.6 Python/2.7.3
Status:403 Forbidden
有没有人能给点建议?
我已经尝试过的事情:
result.ioArgs.xhr.getAllResponseHeaders() // returns string
ioargs.xhr.status // returns the request status.
5 个回答
看起来你是在设置一个叫做 Status:
的头部字段,但你其实想设置的是 Status-Code:
。
你的脚本真的会把 Status Code:200 Script output follows
写成一个头部字段吗?
对于将来遇到这个问题的朋友,原因在于使用的python http.server来提供内容。出于某种原因,它被设计成在cgi脚本开始运行之前
就输出一个Status 200: script output follows
的头信息。这意味着你无法在你的脚本中更改返回的状态码(可以查看这页文档中的CGIHTTPRequestHandler的说明)。
这在开发过程中其实挺麻烦的,因为错误的处理方式和生产环境中不一样。
在输出你的头部信息之前,先用 json.dumps() 把数据转换成字符串,这样就没问题了,对吧?
这样做可以避免在设置头部信息后出现错误,因为在打印的时候出错的可能性很小。
为了补充Jason S所说的内容,我在他的回答中完全重现了同样的问题。我使用了一个不能被转成JSON格式的对象(在这个例子中是一个md5哈希),结果和最初提问的人一样,得到了一个200的返回码。
#!/usr/bin/env python
import json
import traceback
class CGI:
def fire(self):
import md5
return md5.md5()
try:
cgi = CGI()
output = cgi.fire()
print 'Content-Type text/json'
print 'Status:200 success'
print
print json.dumps(output)
except:
traceback.print_exc()
print 'Content-Type: text/json'
print 'Status: 403 Forbidden'
print
print json.dumps({'msg':'error'})
与服务器的交互
$ socat - TCP4:localhost:8000
输入
GET /cgi-bin/test.py HTTP/1.0
输出
HTTP/1.0 200 Script output follows
Server: SimpleHTTP/0.6 Python/3.4.0
Date: Sun, 17 Aug 2014 16:16:19 GMT
Content-Type text/json
Status:200 success
Content-Type: text/json
Status: 403 Forbidden
{"msg": "error"}
错误追踪信息:
127.0.0.1 - - [17/Aug/2014 18:16:19] "GET /cgi-bin/test.py HTTP/1.0" 200 -
Traceback (most recent call last):
File "/home/xcombelle/dev/test/cgi-bin/test.py", line 16, in <module>
print json.dumps(output)
File "/usr/lib/python2.7/json/__init__.py", line 231, in dumps
return _default_encoder.encode(obj)
File "/usr/lib/python2.7/json/encoder.py", line 200, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python2.7/json/encoder.py", line 263, in iterencode
return _iterencode(o, 0)
File "/usr/lib/python2.7/json/encoder.py", line 177, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <md5 HASH object @ 0x7fcb090d0a30> is not JSON serializable
如果 json.dumps(output)
报错了,你已经打印了包括状态码在内的响应头(通常会写成 Status: 200 OK
),然后再加一个空行来结束HTTP响应的头部部分。
接着,except
代码块会打印第二组头部,但这些其实在那时已经算是响应的主体部分了,因为之前的空行已经结束了头部。可以参考一下HTTP消息的规范。
解决办法是等你确定输出内容是什么之后,再打印任何头部信息。
-更多-
json.dumps
在你给它的输入无法被序列化时会报错。而且,cgi.fire()
看起来是某个自定义CGI对象的方法(内置的 cgi
模块没有这个方法),所以它可能返回任何东西。
要调试,你需要记录下是什么异常被抛出,最好能带上错误追踪信息。你现在的 except:
代码块会捕获所有错误,但不会处理它们,这样你就不知道发生了什么,其他人看这个问题也不知道。你可能还需要记录一下 output
的值。