我正在使用CGIHTTPServer.py来创建简单的CGI服务器。如果某些操作出错,我希望我的CGI脚本能够处理响应代码。我怎么能这样做?
我的CGI脚本中的代码段。
if authmxn.authenticate():
stats = Stats()
print "Content-Type: application/json"
print 'Status: 200 OK'
print
print json.dumps(stats.getStats())
else:
print 'Content-Type: application/json'
print 'Status: 403 Forbidden'
print
print json.dumps({'msg': 'request is not authenticated'})
来自请求处理程序的一些代码段
def run_cgi(self):
'''
rest of code
'''
if not os.path.exists(scriptfile):
self.send_error(404, "No such CGI script (%s)" % `scriptname`)
return
if not os.path.isfile(scriptfile):
self.send_error(403, "CGI script is not a plain file (%s)" %
`scriptname`)
return
ispy = self.is_python(scriptname)
if not ispy:
if not (self.have_fork or self.have_popen2):
self.send_error(403, "CGI script is not a Python script (%s)" %
`scriptname`)
return
if not self.is_executable(scriptfile):
self.send_error(403, "CGI script is not executable (%s)" %
`scriptname`)
return
if not self.have_fork:
# Since we're setting the env in the parent, provide empty
# values to override previously set values
for k in ('QUERY_STRING', 'REMOTE_HOST', 'CONTENT_LENGTH',
'HTTP_USER_AGENT', 'HTTP_COOKIE'):
env.setdefault(k, "")
self.send_response(200, "Script output follows") # overrides the headers
decoded_query = query.replace('+', ' ')
答案 0 :(得分:2)
使用标准库HTTP服务器,您无法执行此操作。来自library documentation:
注意CGIHTTPRequestHandler类运行的CGI脚本无法执行重定向(HTTP代码302),因为在执行CGI脚本之前会发送代码200(后面的脚本输出)。这会抢占状态代码。
这意味着服务器不支持脚本中的Status: <status-code> <reason>
标头。您正确识别了代码中显示此支持不存在的部分:服务器甚至在运行脚本之前发送状态代码200。您无法在脚本中更改此内容。
在Python bugtracker中有几个与此相关的票证,其中一些带有补丁,请参阅例如issue13893。因此,您可以选择修补标准库以添加此功能。
但是,我强烈建议您切换到另一种技术而不是CGI(或运行真正的Web服务器)。
答案 1 :(得分:2)
可以实现对覆盖HTTP状态行的Status: code message
标头的支持(HTTP响应的第一行,例如HTTP/1.0 200 OK
)。这需要:
CGIHTTPRequestHandler
进行子类化,以欺骗它将CGI脚本的输出写入StringIO
对象,而不是直接写入套接字。Status:
标题中提供的值更新HTTP状态行。这是一个黑客,但它并不太糟糕,并且不需要修补标准库代码。
import BaseHTTPServer
import SimpleHTTPServer
from CGIHTTPServer import CGIHTTPRequestHandler
from cStringIO import StringIO
class BufferedCGIHTTPRequestHandler(CGIHTTPRequestHandler):
def setup(self):
"""
Arrange for CGI response to be buffered in a StringIO rather than
sent directly to the client.
"""
CGIHTTPRequestHandler.setup(self)
self.original_wfile = self.wfile
self.wfile = StringIO()
# prevent use of os.dup(self.wfile...) forces use of subprocess instead
self.have_fork = False
def run_cgi(self):
"""
Post-process CGI script response before sending to client.
Override HTTP status line with value of "Status:" header, if set.
"""
CGIHTTPRequestHandler.run_cgi(self)
self.wfile.seek(0)
headers = []
for line in self.wfile:
headers.append(line) # includes new line character
if line.strip() == '': # blank line signals end of headers
body = self.wfile.read()
break
elif line.startswith('Status:'):
# Use status header to override premature HTTP status line.
# Header format is: "Status: code message"
status = line.split(':')[1].strip()
headers[0] = '%s %s' % (self.protocol_version, status)
self.original_wfile.write(''.join(headers))
self.original_wfile.write(body)
def test(HandlerClass = BufferedCGIHTTPRequestHandler,
ServerClass = BaseHTTPServer.HTTPServer):
SimpleHTTPServer.test(HandlerClass, ServerClass)
if __name__ == '__main__':
test()
毋庸置疑,这可能不是最好的方法,你应该看一下非CGIHTTPServer解决方案,例如:一个微框架,如bottle
,一个合适的网络服务器(从内存,CGIHTTPServer不推荐用于生产用途),fastcgi或WSGI - 只是举几个选项。