Погуглил по рунету и обнаружил, что нигде нет getting started для того чтобы поднять hunchentoot и заняться наконец веб-программированием на лиспе.

Ну раз нет, то надо написать, люди просят.

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

Итак, начнем с установки всего необходимого:

  1. Устанавливаем sbcl. Что вы делаете, если (он еще) у вас не стоит.
  2. Устанавливаем hunchentoot, например так:

<source lang="lisp"> (require 'asdf-install) (asdf-install:install 'hunchentoot) </source>

  1. Устанавливаем ваши любимые библиотеки.

    Запускаем лисп. Я запускаю его, заходя на сервер по ssh, внутри приятной тулзы screen. И начинаем собственно писать код:

  2. Подгружаем библиотеки (которые вы установили ранее). У меня так:

<source lang="lisp"> (in-package :cl-user) (asdf:operate 'asdf:load-op '#:alexandria) (asdf:operate 'asdf:load-op '#:hunchentoot) (asdf:operate 'asdf:load-op '#:clsql) (asdf:operate 'asdf:load-op '#:closure-template) (asdf:operate 'asdf:load-op '#:split-sequence) (asdf:operate 'asdf:load-op '#:babel) (asdf:operate 'asdf:load-op '#:cl-json) (asdf:operate 'asdf:load-op '#:postmodern) (asdf:operate 'asdf:load-op '#:cl-store) (asdf:operate 'asdf:load-op '#:cl-blackjack) (asdf:operate 'asdf:load-op '#:cl-whores) </source>

  1. Есть переменная, на которую мы будем смотреть, чтобы узнать, выдавать вам ошибки в slime, или героически справляться с ними самостоятельно. Так как у меня может приходить до пяти запросов в секунду и в случае ошибки slime оказывается парализованным выстреливающими сообщениями, я делаю простые функции, чтобы в случае такого epic fail зайти по ssh, выполнить функцию, и разбираться в спокойной обстановке.

    Правда, я не знаю что делать, если в момент появления ошибки я был отключен от сервера. Я догадываюсь о том, что произошла ошибка по увеличению количества потоков "Hunchentoot worker" в Slime Threads, но на моей системе они не дебажатся, хотя должны. Впрочем я на фряхе пока, может быть в этом все и дело. На FreeBSD в sbcl потоки "более другие".

<source lang="lisp"> (defvar catch-errors-p nil)

(defun err-on () (setf catch-errors-p nil))

(defun err-off () (setf catch-errors-p t)) </source>

  1. Создаем свой acceptor, который будет принимать запросы:

<source lang="lisp"> (defclass debuggable-acceptor (hunchentoot:acceptor) ()) </source>

  1. Переопределяем метод hunchentoot:acceptor-request-dispatcher, чтобы добавить всплывание ошибок в отладчике, если catch-errors-p установлена в нужное значение.

<source lang="lisp"> (defmethod hunchentoot:acceptor-request-dispatcher ((acceptor debuggable-acceptor)) (if catch-errors-p (call-next-method) (let ((dispatcher (handler-bind ((error #'invoke-debugger)) (call-next-method)))) (lambda (request) (handler-bind ((error #'invoke-debugger)) (funcall dispatcher request)))))) </source>

  1. Пишем свой диспетчер, который будет разруливать запросы

<source lang="lisp"> (defun dispatcher (request) (let* ((request-host (hunchentoot:host)) (request-full-str (hunchentoot:request-uri request)) (request-parted-list (split-sequence:split-sequence #\? (hunchentoot:request-uri request))) (request-str (string-right-trim "\/" (car request-parted-list)))) (let ((output (cond ((equal "/somepage" request-str) (somepage request)) ((equal "/otherpage" request-str) (otherpage request param)) (t (404page request))))) (setf (hunchentoot:content-type*) "text/html; charset=utf-8") (babel:string-to-octets output :encoding :utf-8)))) </source>

  1. Пишем функции somepage и otherpage, которые отдают конкретные страницы в этом примере. Лично я считаю удобным помещать такое в отдельные пакеты, разбивая по функционалу, но у вас может быть свое мнение на этот счет - я не настаиваю.

<source lang="lisp"> (defun somepage (request) "This is somepage") (defun otherpage (request) "This is otherpage") </source>

  1. Инстанцируем свой acceptor, передавая ему свой диспетчер на нужном вам порту, если необходимо:

<source lang="lisp"> (defvar debuggable-acceptor (make-instance 'debuggable-acceptor

:request-dispatcher 'dispatcher

:port 80)) </source>

  1. Запускаем hunchentoot и запрещаем ему обрабатывать ошибки самостоятельно, без высочайшего соизволения:

<source lang="lisp"> (hunchentoot:start debuggable-acceptor) (setf hunchentoot:*handle-http-errors-p* nil) </source>

  1. Зажигаем огонек в глазах, складываем весь вышеприведенный код в один файл, исполняем в лиспе и заходим на http:://localhost/somepage - чтобы проверить, работает ли все это на самом деле.