我有一个 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 根目录,并且那里存在权限问题。