我正在尝试学习更多关于在 SBCL 中处理套接字和网络连接的知识;所以我为 HTTP 写了一个简单的包装器。到目前为止,它只是制作一个流并执行一个请求,以最终获取网站的标题数据和页面内容。
到目前为止,它的工作还算不错。没有什么可吹嘘的,但它至少奏效了。
但是,我遇到了一个奇怪的问题;我不断收到“400 Bad Request”错误。
起初,我对如何处理 HTTP 请求有些怀疑(或多或少将请求字符串作为函数参数传递),然后我创建了一个函数,用我需要的所有部分格式化查询字符串并将其返回以供使用后来......但我仍然得到错误。
更奇怪的是,错误并非每次都发生。如果我在像 Google 这样的页面上尝试该脚本,我会得到“200 Ok”的返回值......但在其他网站上的其他时间,我会得到“400 Bad Request”。
我确定这是我的代码的问题,但如果我确切知道是什么原因造成的,我会被诅咒的。
这是我正在使用的代码:
(use-package :sb-bsd-sockets)
(defun read-buf-nonblock (buffer stream)
(let ((eof (gensym)))
(do ((i 0 (1+ i))
(c (read-char stream nil eof)
(read-char-no-hang stream nil eof)))
((or (>= i (length buffer)) (not c) (eq c eof)) i)
(setf (elt buffer i) c))))
(defun http-connect (host &optional (port 80))
"Create I/O stream to given host on a specified port"
(let ((socket (make-instance 'inet-socket
:type :stream
:protocol :tcp)))
(socket-connect
socket (car (host-ent-addresses (get-host-by-name host))) port)
(let ((stream (socket-make-stream socket
:input t
:output t
:buffering :none)))
stream)))
(defun http-request (stream request &optional (buffer 1024))
"Perform HTTP request on a specified stream"
(format stream "~a~%~%" request )
(let ((data (make-string buffer)))
(setf data (subseq data 0
(read-buf-nonblock data
stream)))
(princ data)
(> (length data) 0)))
(defun request (host request)
"formated HTTP request"
(format nil "~a HTTP/1.0 Host: ~a" request host))
(defun get-page (host &optional (request "GET /"))
"simple demo to get content of a page"
(let ((stream (http-connect host)))
(http-request stream (request host request)))