首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何将dex:get的输出识别为通用Lisp中的JSON或HTML?

如何将dex:get的输出识别为通用Lisp中的JSON或HTML?
EN

Stack Overflow用户
提问于 2022-04-12 21:31:02
回答 3查看 110关注 0票数 2

我用的是SBCL,Emacs和Slime。此外,我使用的是德克萨多图书馆。因此,我可以执行HTTP请求。其中一些将返回JSON:

代码语言:javascript
复制
CL-USER> (dex:get "http://ip.jsontest.com/")
 "{\"ip\": \"179.878.248.207\"}

其他人将返回HTML:

代码语言:javascript
复制
(dex:get "https://ambrevar.xyz/")
"<!DOCTYPE html>
<html lang=\"en\">
<head>
<!-- 2021-12-29 -->
<meta charset=\"utf-8\">
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
<title>&lrm;</title>
<meta name=\"generator\" content=\"Org mode\">
<meta name=\"author\" content=\"root\">
<link rel=\"stylesheet\" type=\"text/css\" href=\"../dark.css\">
<link rel=\"icon\" type=\"image/x-icon\" href=\"../logo.png\">
</head>
<body>
<div id=\"content\">
<div id=\"outline-container-org4051da4\" class=\"outline-2\">
<h2 id=\"org4051da4\">Contact</h2>
<div class=\"outline-text-2\" id=\"text-org4051da4\">
<ul class=\"org-ul\">
<li>Email: <a href=\"mailto:mail@ambrevar.xyz\">mail@ambrevar.xyz</a></li>
<li>PGP: <a href=\"ambrevar.asc\">0x9BDCF497A4BBCC7F</a></li>
</ul>
</div>
</div>
</div>
</body>
</html>
"

在将结果存储在变量中之后,使用:

代码语言:javascript
复制
CL-USER> (defparameter html-response (dex:get "https://ambrevar.xyz/"))
HTML-RESPONSE

CL-USER> (defparameter json-response (dex:get "http://ip.jsontest.com/"))
JSON-RESPONSE 

我想创建一个函数来检查输出是JSON还是HTML。因此,我执行了以下功能:

代码语言:javascript
复制
(defun html-or-json (response)
  "Check it the server response is HTML or JSON data."
  (cond ((null response) nil)
        ((equal (subseq response 0 1) "<") "html")
        (t "json")))

它的作用是:

代码语言:javascript
复制
CL-USER> (html-or-json json-response)
"json"

CL-USER> (html-or-json html-response)
"html"

然而,在我看来,我的解决方案是丑陋的。最初,我尝试使用handle-case并将答案序列化为JSON。如果它成功了,它将是一个JSON。如果失败,该函数将将对象视为HTML。但是事情并不顺利,因为我不精通handle-case语法。

你能想出一个替代办法来实现这个目标吗?也许使用handle-case

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-04-13 01:48:23

@ignis是对的,您需要使用Content-Type头。要更新代码,还有一些工作要做。

  1. 使用defparameter,部分Dexador响应将被丢弃。

如果在REPL中调用函数dex:get,它将返回4个值:

代码语言:javascript
复制
* (dex:get "http://ip.jsontest.com/")
"{\"ip\": \"xx.xx.xx.xxx\"}                       ;; value 1: IP address
"
200                                               ;; value 2: HTTP code
#<HASH-TABLE :TEST EQUAL :COUNT 6 {100A0EA203}>   ;; value 3: HTTP headers
#<QURI.URI.HTTP:URI-HTTP http://ip.jsontest.com/> ;; value 4: URI

当使用defparameter时,只会将第一个值存储在变量中。

代码语言:javascript
复制
* (defparameter response (dex:get "http://ip.jsontest.com/"))
RESPONSE 
* response
"{\"ip\": \"xx.xx.xx.xx\"} ;; value 1: IP address
"
*

保存所有值的一种方法是使用函数多值表

代码语言:javascript
复制
* (defparameter response (multiple-value-list (dex:get "http://ip.jsontest.com/")))
RESPONSE
* response
("{\"ip\": \"xx.xx.xx.xx\"}                           ;; value 1: IP address
"
 200                                                  ;; value 2: HTTP code
 #<HASH-TABLE :TEST EQUAL :COUNT 6 {100A146813}>      ;; value 3: HTTP headers
 #<QURI.URI.HTTP:URI-HTTP http://ip.jsontest.com/>)   ;; value 4: URI
  1. 从响应中读取Content-Type

您可以编写一个函数,根据去构造-绑定宏从headers获取字段。

代码语言:javascript
复制
(defun get-dex-header (dex-response header)
  (destructuring-bind (raw-response http-code http-headers quri)
      dex-response
    (gethash header http-headers)))

该功能的使用是直截了当的:

代码语言:javascript
复制
* (defparameter json-response (multiple-value-list (dex:get "http://ip.jsontest.com/")))
JSON-RESPONSE
* (get-dex-header json-response "content-type")
"application/json"

* (defparameter html-response (multiple-value-list (dex:get "http://bing.com/")))
HTML-RESPONSE
(get-dex-header html-response "content-type")
"text/html; charset=utf-8"
票数 4
EN

Stack Overflow用户

发布于 2022-04-13 02:40:17

我的回答也会进入“罗伯特”回答的方向。但我会用multiple-value-bind。函数content-type-get怎么样,它类似于get,但在第一个位置返回标头的content-type值。

代码语言:javascript
复制
(defun content-type-get (url) 
  (multiple-value-bind (text http-code http-headers quri x) (dex:get url)
    (values (gethash "content-type" http-headers) 
            text 
            http-code 
            http-header 
            quri 
            x)))

;; this in-addition-content-type-returning get function you can use in return with
;; `multiple-value-bind`. The advantage is that you request the response
;; only once - which ensures speed.

(multiple-value-bind 
  (content-type text http-code http-headers quri x) 
    (content-type-get "http://ip.jsontest.com/")
  (cond ((string= "application/json" content-type) 'do-sth-with-json-text)
        ((string= "text/html; charset=utf-8" content-type) 'do-sth-with-html-text)
        (t 'or-something-else)))
票数 3
EN

Stack Overflow用户

发布于 2022-04-13 11:04:07

例如

代码语言:javascript
复制
(defun dex-dispatch (url)
  (multiple-value-bind (content http-result headers uri) (dex:get url)
    ;; cope with errors perhaps here
    (handle-content-type (intern (string-upcase (gethash headers "content-type"))
                                 (find-package "KEYWORD"))
                         content http-result headers uri)))

(defgeneric handle-content-type (content-type content http-result headers uri))

(defmethod handle-content-type :around (content-type content http-result headers uri)
  (declare (ignorable content-type content headers uri))
  (if (= http-result 200)
      (call-next-method)
    ...))

(defmethod handle-content-type ((content-type eql ':application/json)
                               content http-result headers uri)
  ...)

...
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71849354

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档