使用Common Lisp提供静态文件

时间:2013-12-02 03:53:06

标签: http webserver common-lisp static-files

我正在使用Common Lisp编写一个最小的Web服务器,并希望它能够具备一些基本的静态文件服务能力。这个想法是用于开发,测试和其他低流量情况,因此它不必特别有效。它也不必处理大文件。但是,它必须工作,并且在尝试提供图像时出现此错误:

...
(with-open-file (s path :direction :input :element-type 'octet)
             (let ((buf (make-array (file-length s) :element-type 'octet)))
               (read-sequence buf s)
               (write! (make-instance 
                'response :content-type mime
                :body buf) 
                   sock))
             (socket-close sock))
...

具体来说,它给了我错误

The value 137 is not of type CHARACTER.
   [Condition of type TYPE-ERROR]
...

write!的相关部分看起来像

...
(write-string "Content-Length: " stream) (write (length body) :stream stream) (crlf stream)
(crlf stream)
(write-sequence body stream)
(crlf stream)
...

我尝试将其更改为

...
(write-string "Content-Length: " stream) (write (length body) :stream stream) (crlf stream)
(crlf stream)
(write-string (flexi-streams:octets-to-string body) stream)
(crlf stream)
...

然后错误消失,但客户端获得该文件的错误版本。您可以在上面的代码here周围看到更多上下文。

我做错了什么?

系统构建于:usocket之上,:flexi-streams用于octet。以上是对Hunchentoot采用了一种非常类似的方法(参见静态文件片段here;该代码在事先进行分块和其他一些检查,但在其他方面似乎做了同样的事情)。我正在运行:quicklisp中的最新内容,并在64位Debian stable上运行SBCL 1.0.57.0.debian

1 个答案:

答案 0 :(得分:1)

感谢来自jasom的{​​{1}}和Bike作为答案:

如果要从基于#lisp的服务器提供静态文件,则需要

  1. 包括usocket
  2. 确保在接受
  3. 时创建二进制流
  4. 在执行任何操作之前使流成为二元(否则字符/字符串写入/读取会对您造成错误)
  5. 第一点很容易。请致电flexi-streams,或将(ql:quickload :flexi-streams)添加到#:flexi-streams的{​​{1}}行。

    第二点涉及使用附加参数调用:depends-on

    .asd

    第三,你不需要绕过套接字并在任何地方写socket-accept,而是需要进行(socket-accept ready :element-type 'octet) 调用。

    (socket-stream socket)

    根据您的具体情况,将上述每次写入/读取包装起来或者执行一次(在您致电make-flexi-stream之后)然后将(let ((stream (flex:make-flexi-stream (socket-stream sock) :external-format :utf-8))) ;;; stuff you want to do ) 与套接字。