使用 Clack/ningle 将图像嵌入到 Web 服务器中

Cad*_*dyn 2 webserver http common-lisp binary-data

我正在 Common Lisp 中开发一个小型 Web 服务器,但在包含像 png 这样的二进制数据时遇到了麻烦。为了读取 png 等静态文件,我创建了一个宏,它将根据用户指定的文件类型添加新的 Ningle 路由。这包括一个读取器函数参数,它将从文件名创建数据。它适用于基于文本的文件,如 css、html、js(text/css、text/html、text/js 等)。

\n

如何让 Ningle 读取二进制数据作为内容?

\n

这是我的代码

\n
(defun read-file (&key (filename "index.html"))\n  (let\n      ((in (open filename :if-does-not-exist nil))\n       (out ""))\n    (when in\n      (loop for line = (read-line in nil)\n            while line do\n              (progn\n                (setf out (concatenate 'string out (format nil "~a~%" line)))))\n      (close in)\n      out)))\n\n(defun make-adjustable-string (s)\n               (make-array (length s)\n                           :fill-pointer (length s)\n                           :adjustable t\n                           :initial-contents s\n                           :element-type (array-element-type s)))\n\n(defun read-binary (&key (filename "img/free.png"))\n  (let\n      ((in (open filename :if-does-not-exist nil :external-format :unix :element-type '(unsigned-byte 8)))\n       (out ""))\n    (when in\n      (loop for byte = (read-byte in nil)\n            while byte do\n              (progn\n                (setf out (make-adjustable-string out))\n                (vector-push-extend (code-char byte) out)))\n      (close in)\n      out)))\n\n(defmacro add-static-file-handler (filetype &key (html-type (concatenate 'string "text/" filetype)) (reader-function #'read-file))\n  (setf (ningle:route *app* (concatenate 'string "*/:file." filetype))\n        #'(lambda (params)\n            (let*\n                ((path (car (cdr (assoc :splat params))))\n                 (filename (concatenate 'string path "/" (cdr (assoc :file params)) (concatenate 'string "." filetype)))\n                 (file (funcall reader-function :filename (concatenate 'string "." filename))))\n              (cond\n                (file (list 200 (list :content-type html-type) (list file)))\n                (t (list 404 '(:content-type "text/html") (list (concatenate 'string filename " could not be found")))))))))\n                                     \n(add-static-file-handler "css")\n(add-static-file-handler "html")\n(add-static-file-handler "js")\n(add-static-file-handler "txt" :html-type "text/plain" )\n\n(add-static-file-handler "png" :html-type "image/png" :reader-function read-binary)\n\n
Run Code Online (Sandbox Code Playgroud)\n

首先,这真的很慢。必须有一个更快的方法。\n其次,作为一个例子,当我向它扔一个 10x10 png 时,它会出现:

\n
PNG\n\nIHDR\n\n2\xc3\x8f\xc2\xbdd\xc3\xaaIDAT]1K\xc3\x83p\xc3\x84WP\xc2\xb7BAppt.D\\\\\xc3\x85Upr\xc3\x9c\xc2\xb3\xc2\xba8\xc2\xba%\xc3\x83\xc3\x90\xc3\x89ID5! ADd\xc3\x83?\xc2\xad\xc2\xa9\xc3\x87\xc2\xbbw\xc2\xbc{$\xc2\xbc\xc2\xb7+\xc2\xbb\\\\\xc2\xb7\n                                                                 \xc3\x99\xc3\xa5\xc3\x9345\xc2\xb0\xc3\xa8A$\xc3\x89owvN\xc3\xb9\xc2\xbb:\xc3\x8b2\xc3\x97u\xc3\x87\xc2\xb1={\n                                                                                          \xc3\x97zb\xc3\xa7\xc2\xb2\n\xc3\xab\xc3\x81\xc3\x89\xc2\xa1(\xc2\xa6i8\xc2\xbb:9t\\\\\xc3\x88I\xc2\xb8^%y{$\xc3\x9f\\\\\xc3\x8b\xc2\xb1Y<\xc3\xbb2\xc3\x9dX\xc3\xb7!\xc3\x890\xc3\x98G3\xc3\x9a'?\xc3\xb3\xc3\xb0\xc3\x96 \xc3\xa7aV3\xc3\x82\xc3\xad=\xc3\xacI\xc3\xbc\xc2\xa9\xc2\xbb\xc3\xa2[IEND\xc2\xaeB`\n
Run Code Online (Sandbox Code Playgroud)\n

这似乎有点正确。我的意思是它看起来像一个二进制文件。然而,当在浏览器上查看时,它只是默认的损坏图像图标。

\n

Ale*_*nko 5

最简单的办法就是给宁格尔一个处理一切的机会。只需从处理程序返回一个路径名:

CL-USER> (defvar *app* (make-instance 'ningle:app))
*APP*

CL-USER> (setf (ningle:route *app* "/some.png")
               #P"/Users/art/Downloads/demo.png")
#P"/Users/art/Downloads/demo.png"

CL-USER> (clack:clackup *app*)
Hunchentoot server is started.
Listening on 127.0.0.1:5000.
#S(CLACK.HANDLER::HANDLER
   :SERVER :HUNCHENTOOT
   :ACCEPTOR #<SB-THREAD:THREAD "clack-handler-hunchentoot" RUNNING
                {1017FC2433}>)
Run Code Online (Sandbox Code Playgroud)

剩下的事情由 Ningle 来做:

$ curl -v http://localhost:5000/some.png
* Connected to localhost (127.0.0.1) port 5000 (#0)
> GET /some.png HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Thu, 06 May 2021 20:35:59 GMT
< Server: Hunchentoot 1.3.0
< Content-Length: 50661
< Accept-Ranges: bytes
< Last-Modified: Mon, 19 Apr 2021 08:53:21 GMT
< Content-Type: image/png
<
Warning: Binary output can mess up your terminal
Run Code Online (Sandbox Code Playgroud)