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-casedie 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-caseSyntax 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-TypeHeader verwenden. Es gibt einige Arbeit, um den Code zu aktualisieren.
defparameterwird ein Teil der DexadorAntwort verworfenWenn die Funktion dex:getin 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 defparametervon 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-TypeHeader 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