Как правильно разобрать строки запроса с помощью Twisted (python) - PullRequest
2 голосов
/ 09 декабря 2011

Я пытаюсь реализовать простой витой 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 голосов
/ 09 декабря 2011

Я не знаю, почему вы ожидаете, что ваши urlen-кодированные данные будут декодированы в соответствии с некоторыми нестандартными нестандартными правилами, или почему вы считаете стандартную обработку "странной";[ не является особенным в строках запроса.Какое программное обеспечение декодирует их таким образом?

В любом случае, это на самом деле не 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 голос
/ 09 декабря 2011

Может быть, вместо парсера, как насчет постобработки запроса.args, который вы получаете?

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)

print

{'grid': [{'y': 185, 'x': 17}, {'y': 184, 'x': 18}], 'request': 'loadTiles'}

Обратите внимание, что это также упрощает-элемент перечисляет только 0-е значение элемента и преобразует числовые строки в реальные целые числа.

...