Извлечение заголовков из крошечного веб-фреймворка Python - PullRequest
3 голосов
/ 07 декабря 2008

Я пишу веб-фреймворк для Python, цель которого состоит в том, чтобы быть как можно более «маленьким» (в настоящее время менее 100 строк кода). Вы можете увидеть текущий код на github

По сути, это написано, чтобы быть максимально простым в использовании. Пример "Hello World", как сайт:

from pyerweb import GET, runner

@GET("/")
def index():
    return "<strong>This</strong> would be the output HTML for the URL / "

@GET("/view/([0-9]+?)$")
def view_something(id):
    return "Viewing id %s" % (id) # URL /view/123 would output "Viewing id 123"

runner(url = "/", # url would be from a web server, in actual use
       output_helper = "html_tidy" # run returned HTML though "HTML tidy"

По сути, у вас есть функция, которая возвращает HTML, и декоратор GET отображает это в URL.

Когда вызывается runner(), проверяется каждая оформленная функция, если регулярное выражение URL совпадает с URL запроса, функция запускается, и вывод отправляется в браузер.

Теперь проблема - вывод заголовков. В настоящее время для разработки я просто поставил строку перед вызовом runner(), который выполняет print Content-type:text/html\n - это, очевидно, немного ограничивает ..

Моей первой идеей было сделать так, чтобы функции возвращали dict, что-то вроде ..

@GET("/")
def index():
    return {
        "html": "<html><body>...</body></html>",
        "headers": {"Location":"http://google.com"}
    }

Мне действительно не нравится это - возвращать dict со специально названным ключом не так приятно, как просто возвращать строку ..

Я мог бы проверить, являются ли возвращаемые данные диктом, если это так, используйте returned_data['html'] в качестве выходных данных, если это строка, нет пользовательских заголовков для отправки ... но это означает, что нужно переходить без заголовков (что в большинстве случаев) для заголовков, вам придется изменить функцию возврата с return my_html на return {'html':my_html}, что тоже не очень элегантно ..

После написания этого я обнаружил "Sinatra" - подобную в использовании библиотеку Ruby и посмотрел, как она работает с заголовками:

get "/" do
    content_type 'text/css', :charset => 'utf-8'
end

Кажется, в Python это может быть достаточно красиво:

@GET("/")
def index():
    header("location", "http://google.com")

Чтобы реализовать это, я рассматривал вопрос об изменении способа выполнения функций - вместо простого использования возвращаемого значения я бы изменил sys.stdout на StringIO, чтобы вы могли сделать ..

def index():
    print "<html>"
    print "<head><title>Something</title></head>"
    print "<body>...</body>"
    print "</html>

.. не беспокоясь о соединении нескольких строк вместе. В результате у меня мог бы быть отдельный поток для заголовков, так что вышеприведенная функция header() записала бы в нее что-то вроде:

def header(name, value):
    pyerweb.header_stream.write("%s: %s" % (name, value))

По сути, вопрос в том, как бы вы выводили заголовки из этой веб-платформы (в основном с точки зрения использования , но в меньшей степени реализации)?

Ответы [ 3 ]

5 голосов
/ 07 декабря 2008

Посмотрите на PEP 333 для превосходного шаблона проектирования для очень легкого веб-сервера. Если ваш сервер имеет именно этот API, вы можете использовать его во многих контекстах вместе со многими другими продуктами.

PEP 333 (WSGI) предполагает, что вы не возвращаете страницу напрямую, а предоставляете страницу HTML вызываемому объекту "start_response", который оборачивает ваш HTML в правильный ответ HTTP с соответствующими заголовками.

3 голосов
/ 07 декабря 2008

Вы можете использовать эту идею для возврата dict или строки, но добавить новый декоратор, так что «эволюция» для пользователя будет:

простой html:

@GET("/")
def index():
return "<html><body>...</body></html>"

с постоянными заголовками (один @HEADER для каждого или один из них):

@GET("/")
@HEADER("Location","http://google.com")
def index():
return "<html><body>...</body></html>"

со сложными, может быть, рассчитанными заголовками:

@GET("/")
def index():
return {
    "html": "<html><body>...</body></html>",
    "headers": {"Location":"http://google.com"}
}

декоратор @HEADER () просто изменит возвращаемое значение, поэтому код 'framework' останется простым.

1 голос
/ 07 декабря 2008

Вам следует пересмотреть понятие возврата HTML - заголовки являются частью HTTP . Если вы строите свою среду вокруг потока HTTP, заголовки - это просто строки, которые предшествуют полезной нагрузке HTML.

Пример заголовков из вышеуказанной ссылки:

HTTP/1.1 200 OK
Date: Mon, 23 May 2005 22:38:34 GMT
Server: Apache/1.3.3.7 (Unix)  (Red-Hat/Linux)
Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
Etag: "3f80f-1b6-3e1cb03b"
Accept-Ranges: bytes
Content-Length: 438
Connection: close
Content-Type: text/html; charset=UTF-8

Пример Python см. В реализации BaseHTTPRequestHandler.send_header(keyword, value) .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...