Ich verwende SBCL, Emacs und Slime. Außerdem verwende ich die Bibliothek Dexador. Somit kann ich HTTP-Anfragen ausführen. Einige von ihnen geben JSON zurück:
CL-USER> (dex:get "http://ip.jsontest.com/")
"{\"ip\": \"179.183.248.207\"}
Andere geben HTML zurück:
(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>‎</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>
"
Nach dem Speichern des Ergebnisses in Variablen mit:
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
Ich möchte eine Funktion erstellen, um zu überprüfen, ob die Ausgabe JSON oder HTML ist. Daher habe ich diese Funktion:
(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")))
Es klappt:
CL-USER> (html-or-json json-response)
"json"
CL-USER> (html-or-json html-response)
"html"
Meine Lösungen erscheinen mir jedoch hässlich. Zunächst habe ich versucht, handle-case
die Antwort als JSON zu verwenden und zu serialisieren. Wenn es funktionieren würde, wäre es ein JSON. Wenn dies fehlschlägt, würde die Funktion das Objekt als HTML betrachten. Aber die Dinge liefen nicht gut, da ich mit der handle-case
Syntax nicht vertraut bin.
Fällt Ihnen eine Alternative ein, um dieses Ziel zu erreichen? Vielleicht mit handle-case
?
Lösung des Problems
@ignis volens hat Recht, Sie müssen den Content-Type
Header verwenden. Es gibt einige Arbeit, um den Code zu aktualisieren.
defparameter
wird ein Teil der Dexador
Antwort verworfenWenn die Funktion dex:get
in der REPL aufgerufen wird, gibt sie 4 Werte zurück:
* (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
Bei Verwendung defparameter
von wird nur der erste Wert in der Variablen gespeichert.
* (defparameter response (dex:get "http://ip.jsontest.com/"))
RESPONSE
* response
"{\"ip\": \"xx.xx.xx.xx\"};; value 1: IP address
"
*
Eine Möglichkeit, alle Werte zu speichern, könnte die Verwendung der Funktion MULTIPLE-VALUE-LIST sein
* (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
Content-Type
Header aus der AntwortMan könnte eine Funktion schreiben, um ein Feld aus den HTTP-Headern zu erhalten, basierend auf dem DESTRUCTURING-BIND- Makro.
(defun get-dex-header (dex-response header)
(destructuring-bind (raw-response http-code http-headers quri)
dex-response
(gethash header http-headers)))
Die Verwendung der Funktion ist einfach:
* (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"
Keine Kommentare:
Kommentar veröffentlichen