Проверка формы в Racket - PullRequest
       8

Проверка формы в Racket

3 голосов
/ 06 февраля 2020

Я новичок в Racket, хотя мне до сих пор удавалось поиграть с сервлетами и заставить несколько вещей работать. То, что я хотел бы сделать сейчас, это проверить простой запрос имени пользователя / пароля POST. Я добился успеха в этом через модуль «веб-сервер / формыляры», но функция formlet-process заставляет меня называть все входные данные шаблоном: input_0, input_1, et c. что я считаю неловким и неудобным для каждого элемента ввода, присутствующего в форме. Я не понимаю причины, по которым пользователь не может переопределить автоматическое c наименование HTML входных данных для обработки формулой:

(define (get-username/password request)
  (define login-formlet
    (formlet
      (#%# ,{input-string . => . username}
           ,{input-string . => . password})
      (values username password)))

  (formlet-process login-formlet request))

Приведенная выше функция ожидает запрос POST содержать имя пользователя в ключе input_0 и пароль в ключе input_1, поэтому мой шаблон HTML вынужден называть входные данные "username" как input_0, а "пароль" - input_1 (в противном случае formlet-process будет жаловаться):

<html>
    <head>
        <title>Please login</title>
    </head>
    <body>
        <form action="" method="post">
            <label for="username">Username:</label>
            <input type="text" name="input_0" required>
            <label for="password">Password:</label>
            <input type="password" name="input_1" required>
            <button type="submit" value="Login">Login</button>
        </form>
        <div>
            <p></p>
        </div>
    </body>
</html>

Если есть способ переопределить автоматическое c наименование, я не смог бы его найти (надеюсь, я ничего не пропустил из документов!):

https://docs.racket-lang.org/web-server/formlets.html

Поэтому я решил сделать шаг назад и попытаться выполнить обработку самостоятельно и приземлился по адресу:

https://docs.racket-lang.org/web-server/http.html?q=request-bindings%2Fraw#% 28mod-path._web-server% 2Fhttp% 2Fbindings% 29

, но сама документация не рекомендует его использование (без указания альтернативного необработанного безопасного способа сделать это!), Как это может быть трудно извлечь из него очищенные ценности. Итак, вот мой вопрос: есть ли встроенный способ для правильного и безопасного извлечения / обработки санированных значений из запроса POST, не требуя больше, чем встроенные или простые функции в Racket? Я действительно заинтересован в не в зависимости от любого стороннего пакета или модуля, но от того, что уже предлагает Racket.

Заранее спасибо!

1 Ответ

1 голос
/ 13 февраля 2020

Чтобы начать с последнего вопроса, правильный способ извлечения привязок вручную (который web-server/formlets использует для внутреннего использования) - это request-bindings/raw в сочетании с вспомогательными функциями, которые работают с binding:form и binding:file структуры, такие как bindings-assq-all. Документация, безусловно, должна быть изменена, чтобы более четко указывать на устаревший API.

Что касается формлетов, то шаблон для входных имен является частью дизайна абстракции формы, но это не то, что вы как ожидается, будут взаимодействовать напрямую. Может быть, вы уже знаете это, но, поскольку вы упоминаете formlet-process, но не formlet-display, мне интересно, возможно, вы наткнулись на web-server/formlets, не видя всего этого фона (что легко сделать!). Есть статья academi c , в которой подробно описывается дизайн, но я постараюсь немного разобраться здесь (на примере из статьи).

Представьте, что вы хотите создать компонент формы, чтобы спросить пользователя о дате. Вам нужно написать код для двух разных задач: генерация HTML и обработка отправленного запроса. Однако эти задачи тесно взаимосвязаны. Если вы изменяете HTML, который вы генерируете (который, вероятно, будет включать несколько элементов ввода), вам часто придется вносить соответствующие изменения в код обработки. Нам нужен способ помочь отображению и обработке кода синхронизироваться c. Более того, после того как вы создали отличный компонент даты, вы можете использовать его несколько раз в одной и той же форме: возможно, вы даже захотите создать компонент диапазона дат. Поскольку HTML входные элементы идентифицируются уникальными идентификаторами, вам нужны некоторые средства абстракции, чтобы сделать ваш код многократно используемым.

Formlets предлагают решение этих проблем. Формула инкапсулирует код рендеринга и обработки, сохраняя их в синхронизации c. Чтобы ваши формулы действительно инкапсулировали некоторую функциональную единицу, библиотека web-server/formlets генерирует все идентификаторы.

Это все немного абстрактно, поэтому вот пример использования формул для получения имени пользователя и пароля:

#lang web-server/insta

(require web-server/formlets)

(define (start request)
  (define-values [username password]
    (get-username+password-from-user))
  (redirect/get)
  (response/xexpr
   `(html (head (title "You Logged In")
                  (meta ([charset "utf-8"]))
                  (meta ([name "viewport"]
                         [content "width=device-width,initial-scale=1"])))
            (body (h1 "You Logged In")
                  (p (b "Your username: ") ,username)
                  ;; obviously don't do this for real:
                  (p (b "Your password: ") ,password)))))


(define login-formlet
  (formlet
   (#%# (p (label "Username: "
                  ,{=> (to-string
                        (required
                         (text-input
                          #:attributes '([required "required"]))))
                       username}))
        (p (label "Password: "
                  ,{=> (to-string
                        (required
                         (password-input
                          #:attributes '([required "required"]))))
                       password}))
        (p (input ([type "submit"]
                   [value "Log In"]))))
   (values username password)))

(define (get-username+password-from-user)
  (send/formlet
   login-formlet
   #:wrap
   (λ (rendered-form)
     `(html (head (title "Please Log In")
                  (meta ([charset "utf-8"]))
                  (meta ([name "viewport"]
                         [content "width=device-width,initial-scale=1"])))
            (body (h1 "Please Log In")
                  ,rendered-form)))))
...