Python 如何从CGI脚本发送响应头和状态

Python 如何从CGI脚本发送响应头和状态,python,cgi,Python,Cgi,我使用创建简单的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

我使用创建简单的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('+', ' ')

使用标准库HTTP服务器,您无法执行此操作。从:

注意:CGIHTTPRequestHandler类运行的CGI脚本无法执行重定向(HTTP代码302),因为代码200(后面是脚本输出)是在执行CGI脚本之前发送的。这会优先使用状态代码

这意味着服务器不支持脚本中的
状态:
头。您正确地识别了代码中显示此支持不存在的部分:服务器甚至在运行脚本之前发送状态代码200。您无法在脚本中更改此设置

Python bugtracker中有几个与此相关的标签,有些带有补丁,请参见。因此,您可以选择修补标准库以添加此功能


但是,我强烈建议您切换到另一种技术而不是CGI(或运行真正的web服务器)。

可以实现对覆盖HTTP状态行的
状态:代码消息
头的支持(HTTP响应的第一行,例如
HTTP/1.0 200 OK
)。这需要:

  • 子分类
    cgihtprequesthandler
    ,以诱使其将CGI脚本的输出写入
    StringIO
    对象,而不是直接写入套接字
  • 然后,CGI脚本完成后,使用
    状态:
    标题中提供的值更新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解决方案,例如,一个微型框架,例如,一个合适的web服务器(从内存中,CGIHTTPServer不建议用于生产)、fastcgi或WSGI——仅举几个选项。

    实际上,问题是什么?你所拥有的似乎应该有用。你是说异常处理吗?(在这种情况下,您可以捕获异常并返回http响应代码500 internal server error。@mhawke您可以在上面的注释中查看上面的代码,您将看到它的重写头。您理解问题了吗?太好了……我可以使用WSCGI实现吗?twisted附带了一个内置的web服务器,可以使用
    twistd运行。)-n web--路径。
    当然,它可以在python中扩展: