CherryPy 将查询字符串值与 POST 正文中的表单值相结合
CherryPy combining querystring value with form value in POST body
我正在维护其他人的旧 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() 方法。
据我所知,我正在维护的代码并不总是这样工作。所以这引出了我的两个问题:
- CherryPy 是否在 3.7.0 之前的某个版本(这是我正在测试的版本)中更改了它处理这种情况的方式?
- 我可以配置 CherryPy 恢复到原来的行为,或者至少让 POST 值覆盖查询字符串值吗?
(我对 CherryPy 文档不是很熟悉,但在那里找不到答案。)
我确实得到了你预期的结果。我想你的代码有问题。
你特别使用
% (name, name)
无法解析为两个不同的值。
我不认为这是 3.x 系列的变化。您可以直接访问 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)
我找到了我提出的问题 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 开始,它现在这样做(其中 key
和 value
来自正在处理的 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
当我知道那是我所追求的价值所在时。
我正在维护其他人的旧 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() 方法。
据我所知,我正在维护的代码并不总是这样工作。所以这引出了我的两个问题:
- CherryPy 是否在 3.7.0 之前的某个版本(这是我正在测试的版本)中更改了它处理这种情况的方式?
- 我可以配置 CherryPy 恢复到原来的行为,或者至少让 POST 值覆盖查询字符串值吗?
(我对 CherryPy 文档不是很熟悉,但在那里找不到答案。)
我确实得到了你预期的结果。我想你的代码有问题。
你特别使用
% (name, name)
无法解析为两个不同的值。
我不认为这是 3.x 系列的变化。您可以直接访问 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)
我找到了我提出的问题 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 开始,它现在这样做(其中 key
和 value
来自正在处理的 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
当我知道那是我所追求的价值所在时。