0

私は、署名されたリクエストをReSTful Webサービスに送信し、XMLを受信し、それをHTMLに変換し、AJAX経由でクライアントに配信するブラウザ(と呼びましょうthebrowser)を備えたZope/Ploneサーバーを持っています(したがって、クライアントの観点から) 、すべてが私のサーバー上で行われます)。ほとんどの場合、これは機能しますが、特定の要求では機能しません。その理由はわかりません。失敗したリクエストには数秒かかり、データの長さは約 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取り、path一般的な処理 (署名されたリクエストをhttps://remote.service.somewhere/some/sub/pathに送信する) を実行し、XML レスポンスを に従って正しい変換メソッドに送りpath、 jquery アコーディオンなどで使用されます。

ブラウザ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 (64bit)、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