【问题标题】:CherryPy combining querystring value with form value in POST bodyCherryPy 将查询字符串值与 POST 正文中的表单值组合
【发布时间】:2015-07-09 07:23:21
【问题描述】:

我正在维护别人的旧 CherryPy 代码,并且有一个有趣的情况我正在尝试理解。考虑这个演示它的代码:

import cherrypy

class HelloWorld(object):
    def index(self, name):
        html = """<form method="post">
            <input type="text" name="name" value="%s" /></form>
            Hello %s!""" % (name, name)
        return html
    index.exposed = True

cherrypy.quickstart(HelloWorld())

使用python hello.py 运行它并转到http://127.0.0.1:8080/?name=foo。输出是一个带有“foo”的文本输入框,后跟“Hello foo!”。

但是如果我编辑框中的文本并将其替换为“bar”并按回车(提交表单),则结果不是输入框中的“bar”和“Hello bar!”下面但是(ascii艺术输入框道歉):

 +---------------------+
 | [u'foo', u'bar']    |
 +---------------------+

 Hello [u'foo', u'bar']!

CherryPy 似乎正在将 URL 查询字符串“name”参数值与 POST 请求正文中提交的表单“name”值结合起来,并为公开的 index() 方法提供一个包含这两个值的列表。

就我所维护的代码而言,它并不总是以这种方式工作。所以这就引出了我的两个问题:

  1. CherryPy 在 3.7.0 之前的某些版本(我正在测试的版本)中是否改变了处理这种情况的方式?
  2. 我可以将 CherryPy 配置为恢复到旧的行为,或者至少让 POST 值覆盖查询字符串值吗?

(我对 CherryPy 文档并不十分熟悉,但我无法在那里找到答案。)

【问题讨论】:

  • 问题可能是您的浏览器处理占位符文本与自动填充表单字段的方式存在冲突。

标签: python forms query-string cherrypy


【解决方案1】:

我找到了我提出的问题 1 的答案。

随着 CherryPy 3.2 的发布,行为发生了变化。实际更改是在 2009 年 5 月 31 日在 git commit e05feef4fee7df1ee5d25d11393f872c9ef12510 (hg:3b92b5aa76f9) 中进行的,当时 _cpreqbody 模块被切换以代替旧的 process_body() 方法。

用于执行此操作的代码(其中 self.params 是一个字典,已包含查询字符串中的参数):

        self.body_params = p = httputil.params_from_CGI_form(forms)
        self.params.update(p)

从 3.2 开始,它现在执行此操作(其中 keyvalue 来自正在处理的 POST 正文):

        if key in params:
            if not isinstance(params[key], list):
                params[key] = [params[key]]
            params[key].append(value)
        else:
            params[key] = value

我的问题 2 似乎没有简单的答案,所以当我知道我所追求的价值会在哪里找到时,我将不得不使用 cherrypy.request.body_params

【讨论】:

  • 顺便说一句,git 不是唯一的 VCS,尤其是考虑到提交哈希前面的小 hg: ;-)
  • 我给 git 和 hg 提交都提供了哈希值,看到项目在某个时候切换了。
  • 我猜the official repo 仍在 BitBucket 上,cherrypy.org 指向它。在 GitHub,它是一面镜子。不过,我可能会再次错过一些东西;-)
【解决方案2】:

我不认为这是 3.x 系列的变化。您可以像下面的 sn-p 一样直接访问 GET 和 POST 参数。但是,更建议使用唯一名称且不易出错。

import urlparse
import cherrypy

class HelloWorld:

  @cherrypy.expose
  def index(self, name):
    postParams = cherrypy.request.body.params
    getParams  = urlparse.parse_qs(cherrypy.request.query_string)
    print(postParams, getParams)
    # ({u'name': u'bar'}, {'name': ['foo']})

更新

很好的研究@TimB。通过跳过代码库,我找不到事情发生的地方。是的,CherryPy 3.2+ 就像这个系列一样。

CherryPy 是完全可配置的,当您能够处理它的概念时,您的情况也不例外。具体来说,您可以编写一个 CherryPy 工具来使用 POST 参数覆盖混合请求参数。就那么几行。

#!/usr/bin/env python
# -*- coding: utf-8 -*-


import urlparse

import cherrypy


config = {
  'global' : {
    'server.socket_host' : '127.0.0.1',
    'server.socket_port' : 8080,
    'server.thread_pool' : 8
  },
  '/' : {
     'tools.postoverride.on' : True,
   }
}

def postOverride():
  cherrypy.request.params.update(cherrypy.request.body.params)

cherrypy.tools.postoverride = cherrypy.Tool('before_handler', postOverride)


class HelloWorld:

  @cherrypy.expose
  def index(self, name):
    html = """<form method="post">
      <input type="text" name="name" value="%s" /></form>
      Hello %s!""" % (name, name)
    return html


if __name__ == '__main__':
  cherrypy.quickstart(HelloWorld(), '/', config)

【讨论】:

  • 我希望避免进行这样的更改,因为我认为这个问题出现在我继承的代码库中的大多数公开方法中。这就是我问问题 2 的原因。
  • 谢谢@saaj;我用一个工具做了类似的事情,虽然你的更简单。
【解决方案3】:

我确实得到了您的预期结果。我想你的代码有问题。

特别是你使用

% (name, name)

无法解析为两个不同的值。

【讨论】:

  • 我已经澄清了这个问题,以明确name 在您引用的代码及其生成的输出中具有相同的值。
  • 我对代码做了一点改动,这对我来说产生了相同的结果。你仍然得到预期的结果吗?
猜你喜欢
  • 2018-08-14
  • 2021-11-11
  • 1970-01-01
  • 2017-11-24
  • 2014-04-11
  • 2012-10-26
  • 2014-01-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多