我有一个 clojure 环服务器,我想将数据发布到其中,这样我就可以在数据库中执行操作,例如添加、更新和删除用户。我目前坚持以我可以方便使用的格式接收正文(按键图)。
我有 NodeJS 背景,您可以通过添加 body-parser 中间件轻松访问请求正文。
这是代码
(ns questhero.core
(:require
[ring.adapter.jetty :as jetty]
[cheshire.core :refer [generate-string]]
[ring.middleware.cors :refer [wrap-cors]]
[ring.util.request]
[ring.util.io]
[ring.middleware.defaults :refer [wrap-defaults site-defaults]]))
(defn create-user [request]
(let [body (slurp (:body request))]
(println "body" body)
{:status 200
:headers {"Content-Type" "application/json"}
:body (generate-string {:message "Success"})}))
(defn handler [{:keys [uri] :as request}]
(cond
(= uri "/create-user")
(create-user request)
:else
{:status 404
:headers {"Content-Type" "application/json"}
:body "Not Found"}))
(def allowed-origins [#"http://localhost:3000"])
(def allowed-methods [:get :post :put :delete])
(def allowed-headers #{:accept :content-type})
(def app
(-> #'handler
(wrap-defaults (assoc-in site-defaults [:security :anti-forgery] false))
(wrap-cors :access-control-allow-origin allowed-origins
:access-control-allow-methods allowed-methods
:access-control-allow-headers allowed-headers)))
(defn start-server []
(println "listening server")
(jetty/run-jetty app {:port 4000}))
(println "starting server")
(start-server)
当我发布到创建用户路由时,正文被记录为
["^","~:fullname","myfullname","~:username","myusername","~:email","[email protected]","~:password","mypassword1234"]
如何将其转换为对象键映射?
我还希望能够通过打印到终端来检查正文的内容,这可能是嵌套地图
有关更多信息,这就是我的 clojurescript 前端请求的样子
(defn post-save-new-user [data]
(ajax/POST "http://localhost:4000/create-user"
{:handler handle-response
:error-handler handle-error
:headers {"Accept" "application/json"
"Content-Type" "application/json"}
:params data}))
我尝试添加以下环形中间件wrap-params、wrap-json-body和wrap-json-params,但没有任何帮助。
我也尝试过这个answer
的步骤如果您不想使用框架或预先编写的中间件,您可以使用 Cheshire 来解析您在处理程序中读取的正文字符串:
(ns questhero.core
(:require
[cheshire.core :refer [generate-string parse-string]]
[clojure.pprint :refer [pprint]]
[ring.adapter.jetty :as jetty]
[ring.middleware.cors :refer [wrap-cors]]
[ring.middleware.defaults :refer [wrap-defaults site-defaults]]
[ring.util.request]
[ring.util.io]))
(defn create-user [request]
(let [body (slurp (:body request))
body-params (parse-string body true)]
(println "body" body)
(pprint body-params)
{:status 200
:headers {"Content-Type" "application/json"}
:body (generate-string {:message "Success"})}))
请注意,这里我已将
parse-string
添加到 Cheshire 的引用函数中,以及来自 pprint
命名空间的 clojure.pprint
。传递给 parse-string
的布尔值将所有键转换为关键字。
需要注意的一件事是,请求的主体是一个 Java InputStream,这意味着它是有状态的。如果您
slurp
它,它将被消耗,并且无法再次读取。这是考虑使用只读取一次主体的中间件的原因之一。我将在这里给您举一个例子,但这只是最基本的内容协商。它不适用于非 JSON 编码数据,但普通 URL 编码表单参数除外,这些参数由您已使用并放入的默认中间件处理 :form-params
:
(defn wrap-json-body [handler]
(fn [request]
(if (= (ring.util.request.content-type request)
"application/json"))
(let [body-params (-> request
:body
slurp
(parse-string true)]
(handler (assoc request :body-params body-params)))
(handler request))
这将像第一个示例中那样解析正文,并将解析的参数放在请求中的 :body-params 中。如果您想以相同的方式对待查询参数和 JSON 主体,您可能需要将处理程序调用交换为:
(handler (-> request
(update :params merge body-params)
(assoc :body-params body-params)))
现在您可以将此中间件添加到您的应用程序中:
(def app
(-> #'handler
(wrap-json-body)
(wrap-defaults (assoc-in site-defaults [:security :anti-forgery] false))
(wrap-cors :access-control-allow-origin allowed-origins
:access-control-allow-methods allowed-methods
:access-control-allow-headers allowed-headers)))