如何正确解析Twisted(python)的请求字符串
我正在尝试实现一个简单的扭曲HTTP服务器,它可以响应从数据库加载瓦片的请求并返回它们。不过,我发现它对请求字符串的解析方式有点奇怪。
这是我发送给服务器的内容:
curl -d "request=loadTiles&grid[0][x]=17&grid[0][y]=185&grid[1][x]=18&grid[1][y]=184" http://localhost:8080/fetch/
我期望的request.args
是这样的:
{'request': 'loadTiles', 'grid': [{'x': 17, 'y': 185}, {'x': 18, 'y': 184}]}
但是Twisted对request.args
的解析结果是这样的:
{'grid[1][y]': ['184'], 'grid[0][y]': ['185'], 'grid[1][x]': ['18'], 'request': ['loadTiles'], 'grid[0][x]': ['17']}
请问有没有办法让它自动解析请求字符串,并为网格参数创建一个列表,还是说我必须手动去做?
我可以把网格参数进行JSON编码,然后在服务器端解码,但这看起来像是一个不必要的变通方法。
2 个回答
4
我不明白你为什么会期待你的 URL 编码数据按照一些临时的非标准规则被解码,或者为什么你会觉得标准的处理方式“奇怪”;在查询字符串中,[
并没有什么特别的。是什么软件会这样解码它们呢?
无论如何,这其实不是 Twisted 的问题,而是 Python 的问题(更广泛来说,是 网络标准 解析这些数据的方式)。你可以通过 cgi.parse_qs
函数来互动查看你会得到什么样的数据。例如:
>>> import cgi
>>> cgi.parse_qs("")
{}
>>> cgi.parse_qs("x=1")
{'x': ['1']}
>>> cgi.parse_qs("x[something]=1")
{'x[something]': ['1']}
>>> cgi.parse_qs("x=1&y=2")
{'y': ['2'], 'x': ['1']}
>>> cgi.parse_qs("x=1&y=2&x=3")
{'y': ['2'], 'x': ['1', '3']}
希望这能帮你理清一些问题。
1
也许我们可以考虑用一种方法来处理你收到的请求参数,而不是使用解析器。
from pyparsing import Suppress, alphas, alphanums, nums, Word
from itertools import groupby
# you could do this with regular expressions too, if you prefer
LBRACK,RBRACK = map(Suppress, '[]')
ident = Word('_' + alphas, '_' + alphanums)
integer = Word(nums).setParseAction(lambda t : int(t[0]))
subscriptedRef = ident + 2*(LBRACK + (ident | integer) + RBRACK)
def simplify_value(v):
if isinstance(v,list) and len(v)==1:
return simplify_value(v[0])
if v == integer:
return int(v)
return v
def regroup_args(dd):
ret = {}
subscripts = []
for k,v in dd.items():
# this is a pyparsing short-cut to see if a string matches a pattern
# I also used it above in simplify_value to test for integerness of a string
if k == subscriptedRef:
subscripts.append(tuple(subscriptedRef.parseString(k))+
(simplify_value(v),))
else:
ret[k] = simplify_value(v)
# sort all the matched subscripted args, and then use groupby to
# group by name and list index
# this assumes all indexes 0-n are present in the parsed arguments
subscripts.sort()
for name,nameitems in groupby(subscripts, key=lambda x:x[0]):
ret[name] = []
for idx,idxitems in groupby(nameitems, key=lambda x:x[1]):
idd = {}
for item in idxitems:
name, i, attr, val = item
idd[attr] = val
ret[name].append(idd)
return ret
request_args = {'grid[1][y]': ['184'], 'grid[0][y]': ['185'], 'grid[1][x]': ['18'], 'request': ['loadTiles'], 'grid[0][x]': ['17']}
print regroup_args(request_args)
打印输出
{'grid': [{'y': 185, 'x': 17}, {'y': 184, 'x': 18}], 'request': 'loadTiles'}
请注意,这样做还可以把只有一个元素的列表简化为这个元素的值,并将数字字符串转换成真正的整数。