0

我有一个 Zope/Plone 服务器,它有一个浏览器(我们称之为thebrowser),它将签名请求发送到 ReSTful Web 服务,接收 XML,将其转换为 HTML 并通过 AJAX 将其传递给客户端(因此,从客户端的角度来看,一切都发生在我的服务器上)。大多数情况下这是有效的,但对于某些请求它不会,我不知道为什么。失败的请求需要几秒钟,数据长度约为 100 kB,但我们这里不是在谈论分钟或兆字节。

奇怪的是,该ZServerHTTPResponse对象看起来还不错,但它以空字符串的形式到达 Web 客户端(Firefox、Firebug)!

工具链如下所示:

在皮肤中,我有一个Script (Python)

## Script (Python) "theservice"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind subpath=traverse_subpath
##parameters=
##title=
##
thebrowser = context.getBrowser('thebrowser')
return thebrowser.get(thedict={'path':'/'.join(traverse_subpath)})

这使得请求/theservice/some/sub/path起作用;some/sub/path放在path钥匙里。

get方法thebrowser接受参数,进行一般处理(向https://remote.service.somewhere/some/sub/pathpath发送签名请求),根据 将 XML 响应提供给正确的转换方法,并返回响应,例如由 jquery 手风琴使用。path

浏览器thebrowser看起来像这样(为清楚起见,删除了错误处理等):

def transformer(func):
    """
    decorator function for generic processing
    """
    def f2(self, txt, req=None, auth_tup=None):
        global HTML_HEAD, HTML_TAIL
        ham = func(self, txt, auth_tup=auth_tup)
        res = list(HTML_HEAD)
        res.extend(ham)
        res.extend(HTML_TAIL)
        return u''.join(res)

    f2.__name__ = func.__name__
    return f2

class Browser(BrowserView):

    def get(self, propagate=True, thedict=None):
        """
        send a request to the remote ReSTful service
        and transform the received XML text to HTML

        pretty URL:
        /theservice/path/as/sub/path
        """
        context = self.context
        request = context.request
        response = request.response
        if thedict is None:
            thedict = request.form
        path = thedict['path']
        # ... set the 'pseudonym', 'theurl' variables ...
        auth_tuples = self._auth_tuples(pseudonym)
        code = None
        text = None
        fo = urlopen(theurl)
        code = fo.code
        headers = fo.info().headers
        # set the headers explicitly; might be unnecessary:
        for line in headers:
            name, text = line.split(':', 1) # found: ': '
            handle_header(response, name, text)
        raw = fo.read().strip()
        text = unicode(raw, 'utf-8')   # -> unicode
        fo.close()
        text = self.transform(path, text, response, theurl, auth_tuples)
        response.setBody(text)
        return response
        # -------------------------------------------------------- get

    def transform(self, path, txt, response, theurl=None, auth_tup=None):
        """
        Choose a transformer function, apply it to the given text,
        and return the HTML text generated
        """
        transformer = self.getTransformer(path) # not included here
        html = transformer(self,                # e.g. tf_xy; see below
                           txt.decode('utf-8'),
                           theurl or path,
                           auth_tup=auth_tup)
        if html is not None:
            response.setHeader('Content-Type', 'text/html; charset=utf-8')
            return html
        return txt.encode('utf-8')

    @transformer
    def tf_xy(self, txt, auth_tup=None):
        """
        transform function for path xy
        """
        root = ElementTree.fromstring(txt)
        res = []
        for child in root.getchildren():
            if child.tag == 'foo':
                res.append(''.join(('<p>', child.text, '</p>'))) # example
            # ...
        return res

当我对get方法应用另一个装饰器来记录结果时,我得到了有关该ZServerHTTPResponse对象的以下信息:

headers = {'connection': 'close',
           'content-length': '110626',
           'content-type': 'text/html; charset=utf-8',
           'date': 'Wed, 17 Apr 2013 09:04:13 GMT',
           'status': '200 OK',
           'transfer-encoding': 'chunked'}
accumulated_headers = 'Set-Cookie: JSESSIONID=471108159E6EF40EB9F2F7305E77EB69; Path=/; Secure\r\n'
body = '<!DOCTYPE html><html><head><meta h(... 110575 bytes total ...)iv></body></html>'
errmsg = 'OK'
status = 200

...这对我来说看起来很合理。无论如何,对于某些请求(可能是响应较大或处理时间最长的请求),客户端浏览器会看到一个空字符串。

版本:Zope 2.10.13、Python 2.4.6(64 位)、Plone 3.3(是的,我们将切换到 Plone 4,但这需要一些时间......)

更新: 当我修复ElementTree导入以使用编译版本时,我认为我的问题已经解决:

try:
    from celementtree import fromstring        # modern Python versions
except ImportError:
    try:
        from cElementTree import fromstring    # Python 2.4
    except ImportError:
        from elementtree import fromstring     # emergency fallback

不幸的是,这对我有用,但对客户无效。

Zope 站点在通常的 RewriteRule 处于活动状态的 Apache VirtualHost 中提供服务:

RewriteRule ^/(.*) http://localhost:8082/VirtualHostBase/http/%{HTTP_HOST}:80/theportalroot/VirtualHostRoot/$1 [L,P]

根据 Firebug,不存在 content-length 标头(这可以被 Apache 剥离吗?!)。以下是完整的响应标头:

Connection          Keep-Alive
Content-Encoding    gzip
Content-Type        text/html; charset=utf-8
Date                Thu, 18 Apr 2013 12:31:41 GMT
Keep-Alive          timeout=15, max=99
Server              Zope/(Zope 2.10.7-final, python 2.4.6, linux2) ZServer/1.1 Plone/3.2.2 ShellEx Server/4.0.0
Set-Cookie          JSESSIONID=308B09957635CA02829AF5C362FB60E3; Path=/; Secure
Transfer-Encoding   chunked
Vary                Accept-Encoding

我尝试直接通过 Zope 获得响应,但要做到这一点,我显然必须访问 Zope 根目录,并且那里存在权限问题。

4

0 回答 0