Отправка Hunchentoot методом HTTP

Я не смог найти никакой документации о том, как выполнять отправку на основе метода HTTP (по тому же uri). Ближайшее, что я получил, было :default-request-type на define-easy-handler, но, похоже, оно отправляется последнему, хотя я использую метод GET:

(define-easy-handler (index :uri "/" :default-request-type :get) ()
  (log-message* :info "GET on index ------ ")
  (format nil "Hello World"))

(define-easy-handler (echo :uri "/" :default-request-type :post) ()
  (log-message* :info "POST on index ------ ")
  (format nil "~S" (raw-post-data :force-text t)))

person mck    schedule 27.09.2013    source источник
comment
Из исходного кода может показаться, что default-requiest-type влияет только на то, какие аргументы учитываются при вызове обработчика. Это не влияет на то, будет ли вызван обработчик. Так что похоже, что вы сами реализуете это.   -  person    schedule 28.09.2013
comment
Спасибо, что заглянули в источник для меня :) Думаю, мне придется что-то реализовать для этого самостоятельно.   -  person mck    schedule 30.09.2013


Ответы (3)


Параметр :uri (возможно, слегка обманчиво названный) может быть либо строкой, либо предикатом объекта запроса. Таким образом, вы можете передать туда функцию, которая проверяет, совпадают ли метод и путь. Я написал макрос, чтобы сделать его красивее:

(defmacro method-path (methods path)
  "Expands to a predicate the returns true of the Hunchtoot request
has a SCRIPT-NAME matching the PATH and METHOD in the list of METHODS.
You may pass a single method as a designator for the list containing
only that method."
  (declare
   (type (or keyword list) methods)
   (type string path))
  `(lambda (request)
     (and (member (hunchentoot:request-method* request)
                 ,(if (keywordp methods)
                      `'(,methods)
                      `',methods))
          (string= (hunchentoot:script-name* request)
                   ,path))))

(hunchentoot:define-easy-handler (get-handler :uri (method-path :get "/hello")) ()
  "hello!")

(hunchentoot:define-easy-handler (post-handler :uri (method-path (:post :put) "/hello")) ()
  "a post or a put!")

В случае, когда путь найден, а метод нет, нам, вероятно, следует вернуть ошибку HTTP 405 вместо ошибки 404, которую возвращает Hunchentoot, когда нет соответствующих обработчиков. Чтобы сделать это, вы можете вручную написать универсальный обработчик для каждого пути, который вы определяете. Предполагается, что ответ 405 включает список допустимых методов, и я не могу придумать простой способ сгенерировать один, кроме изменения define-easy-handler, чтобы напрямую поддерживать специализацию по методу, что может быть хорошей идеей.

person Samuel Edwin Ward    schedule 18.10.2014

Это есть во многих фреймворках, построенных на основе Hunchentoot. Рестас и Пещерный человек — всего лишь два примера. Например, в Restas вы можете сказать:

(restas:define-route foo ("/foo" :method :get)
  ; some code here
  )

(restas:define-route foo/post ("/foo" :method :post)
  ; some other code here
  )
person Pavel Penev    schedule 11.10.2013
comment
Спасибо за подсказки. Я пробовал использовать Caveman, но вернулся к Hunchentoot после этой проблемы. - person mck; 12.10.2013

Теперь у нас есть надстройка Hunchentoot, которая делает именно это: easy-routes. Он обеспечивает отправку по методу HTTP, извлечение аргументов из пути URL и удобную нотацию декоратора.

Чтобы использовать его, нам просто нужно использовать его routes-acceptor вместо стандартного easy-acceptor:

(hunchentoot:start (make-instance 'easy-routes:routes-acceptor))

Пример:

(defroute foo ("/foo/:arg1/:arg2" :method :get)
   (&get w)
    (format nil "<h1>FOO arg1: ~a arg2: ~a ~a</h1>" arg1 arg2 w))
person Ehvince    schedule 16.10.2019