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)))

2 ответа

(Возможно, слегка обманчиво названный) :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 поддерживать специализацию на методе напрямую, что может быть хорошей идеей.

Многие фреймворки, построенные поверх hunchentoot, имеют это. Рестас и Пещерный человек - только два примера. Например, в Рестас вы можете сказать:

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

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

Теперь у нас есть надстройка 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))
Другие вопросы по тегам