如何在 GAE 中覆盖 HTTP 请求动词

发布于 2024-07-07 12:10:18 字数 740 浏览 10 评论 0原文

在 Google App Engine Webapp 框架应用程序的上下文中:

我想在以下情况下更改请求的请求动词: 提供参数_method,例如如果有POST请求进来 使用参数 _method=PUT,我需要更改请求来调用 处理程序的 put 方法。 这是应对prototype.js的方式 适用于 PUT 和 DELETE 等动词(IE 的解决方法)。 这是我的 第一次尝试:

class MyRequestHandler(webapp.RequestHandler):
   def initialize(self, request, response):
       m = request.get('_method')
       if m:
           request.method = m.upper()
       webapp.RequestHandler.initialize(self, request, response)

问题是,由于某种原因,每当重定向完成时, self.request.params 在处理方法(put 或 delete) 被调用,即使它们在初始化时被填充 叫。 有人知道这是为什么吗? 作为一种解决方法,我想我 可以在initialize()时克隆参数,但是.copy()不起作用, 我也没有找到办法做到这一点。

更新:我收到了来自 Arachnid 的非常有帮助的回复。 我最终得到的解决方案使用元类。 可以在下面找到。

In the context of a Google App Engine Webapp framework application:

I want to changed the request verb of a request in the case a
parameter _method is provided, for example if a POST request comes in
with a parameter _method=PUT, I need to change the request to call the
put method of the handler. This is to cope with the way prototype.js
works with verbs like PUT and DELETE(workaround for IE). Here is my
first attempt:

class MyRequestHandler(webapp.RequestHandler):
   def initialize(self, request, response):
       m = request.get('_method')
       if m:
           request.method = m.upper()
       webapp.RequestHandler.initialize(self, request, response)

The problem is, for some reason whenever the redirect is done, the
self.request.params are emptied by the time the handling method(put or
delete) is called, even though they were populated when initialize was
called. Anyone have a clue why this is? As a workaround I thought I
could clone the params at initialize() time, but .copy() did not work,
and I haven't found a way to do that either.

Update: I received a very helpful response from Arachnid. The solution I ended up with uses a metaclass. It is found below.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

暖阳 2024-07-14 12:10:18

无论如何,从初始化调用处理程序都不是正确的方法 - 如果这样做,Web 应用程序也会调用原始处理程序。

相反,您有几个选择:

  • 您可以子类化 webapp.WSGIApplication 并重写 call 以基于 _method(如果存在)选择方法。
  • 您可以在initialize中检查_method是否存在,如果存在,则相应地修改请求对象的'REQUEST_METHOD'环境变量。 这将导致 WSGIApplication 类执行您选择的方法。

无论哪种方式,请查看 SDK 中的 google/appengine/ext/webapp/init.py,以便了解其工作原理。

Calling the handler from initialize isn't the right way anyway - if you do that, the webapp will then call the original handler as well.

Instead, you have a couple of options:

  • You can subclass webapp.WSGIApplication and override call to select the method based on _method when it exists.
  • You can check for the existence of _method in initialize, and if it exists, modify the request object's 'REQUEST_METHOD' environment variable accordingly. That will cause the WSGIApplication class to execute the method you choose.

Either way, take a look at google/appengine/ext/webapp/init.py in the SDK so you can see how it works.

蓝海 2024-07-14 12:10:18

这就是 Arachnid 的回答。 向我指出该框架的来源确实很有帮助。 最后我查看了源代码不存在(只有.pyc),也许它随着新版本的SDK而改变了。 对于我的情况,我认为重写 WSGIApplication 是正确的做法。 但是,我选择使用元类,因为它不需要我将一堆框架代码复制(复制)到我的代码中,然后修改它。 这是我的解决方案:

class RequestHandlerMetaclass(type):
    def __init__(cls, name, bases, dct):
        super(RequestHandlerMetaclass, cls).__init__(name, bases, dct)
        org_post = getattr(cls, 'post')
        def post(self, *params, **kws):
            verb = self.request.get('_method')
            if verb:
                verb = verb.upper()
                if verb ==  'DELETE':
                    self.delete(*params, **kws)
                elif verb == 'PUT':
                    self.put(*params, **kws)
            else:
                org_post(self, *params, **kws)
        setattr(cls, 'post', post)

class MyRequestHandler(webapp.RequestHandler):
    __metaclass__ = RequestHandlerMetaclass

Thats Arachnid for your response. Pointing me to the source of the framework was really helpful. Last I looked the source wasn't there(there was only .pyc), maybe it changed with the new version of the SDK. For my situation I think overriding WSGIApplication would have been the right thing to do. However, I chose to use a metaclass instead, because it didn't require me to cargo-cult(copy) a bunch of the framework code into my code and then modifying it. This is my solution:

class RequestHandlerMetaclass(type):
    def __init__(cls, name, bases, dct):
        super(RequestHandlerMetaclass, cls).__init__(name, bases, dct)
        org_post = getattr(cls, 'post')
        def post(self, *params, **kws):
            verb = self.request.get('_method')
            if verb:
                verb = verb.upper()
                if verb ==  'DELETE':
                    self.delete(*params, **kws)
                elif verb == 'PUT':
                    self.put(*params, **kws)
            else:
                org_post(self, *params, **kws)
        setattr(cls, 'post', post)

class MyRequestHandler(webapp.RequestHandler):
    __metaclass__ = RequestHandlerMetaclass
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文