Clojure 无法解析此服务器请求中的EDN

Clojure 无法解析此服务器请求中的EDN,clojure,ring,Clojure,Ring,我认为我做得不错,但我无法将我的EDN从:body输入流中取出。Ring和Compojure处理程序如下所示: 依赖项: [ring.middleware.params :as params] [ring.middleware.edn :as edn]; https://github.com/tailrecursion/ring-edn 处理程序: (defroutes ajax-example (PUT "/ajax-example" r (println r)

我认为我做得不错,但我无法将我的EDN从
:body
输入流中取出。Ring和Compojure处理程序如下所示:

依赖项:

 [ring.middleware.params :as params]
 [ring.middleware.edn :as edn]; https://github.com/tailrecursion/ring-edn
处理程序:

(defroutes ajax-example
  (PUT "/ajax-example" r
       (println r)
       {:status 200
        :headers {"Content-Type" "application/edn"}
        :body "yo"}))
我把它包装成:

  (def ajax-wrapped
   (-> ajax-example
      edn/wrap-edn-params
      params/wrap-params))
根据我发送的简单测试图,
println
'd响应正确地显示它是EDN,并且内容长度是正确的,但是地图本身不存在,它永远被困在
:body
的输入流中。。。如何做到这一点

以下是println的响应:

{:ssl客户端证书为零,:远程地址0:0:0:0:0:1,:参数{},:路由参数{},:标题{来源,主机本地主机:6542,用户代理Mozilla/5.0(Macintosh;Intel Mac OS X 10_10_3)AppleWebKit/537.36(KHTML,像Gecko)Chrome/42.0.2311.135 Safari/537.36,内容类型应用程序/edn,cookie_ga=GA1.1.1354518981.1429622648;内容长度20,引用器,连接保持活动,接受/接受语言en-US,en;q=0.8,sq;q=0.6,接受编码gzip,deflate,sdch,缓存控制最大年龄=0},:服务器端口6542,:内容长度20,:表单参数{},:查询参数{},:content-type-application/edn,:character-encoding-nil,:uri/ajax-example,:server-name-localhost,:query-string-nil,:body#,:edn-params-nil,:scheme:http,:request-method:put}

上方的:主体未正确粘贴,如下所示:

 [open corner bracket] HttpInput org.eclipse.jetty.server.HttpInput@5d969109 [end corner bracket]
使用
cljs ajax
lib从浏览器发送的客户端代码是:

(defn ajax-send
  []
  (let [push {:adder1 2 :add2 3}]
    (PUT "/ajax-example" 
         {:format :edn 
          :params push
          :handler ajax-result
          :error-handler error-handler})))
以下是其中一个答案建议的测试输出:

hf.examples> ((-> ajax-example  params/wrap-params edn/wrap-edn-params) (-> (mock/request :put "/ajax-example")
                                                             (mock/content-type "application/edn")
                                                             (mock/body "{:hello \"there\"}"))) 
{:status 200,
 :headers {"Content-Type" "application/edn"},
 :body
 "{:remote-addr \"localhost\", :params {:hello \"there\"}, :route-params {}, :headers {\"content-length\" \"16\", \"content-type\" \"application/edn\", \"host\" \"localhost\"}, :server-port 80, :content-length 16, :form-params {}, :query-params {}, :content-type \"application/edn\", :uri \"/ajax-example\", :server-name \"localhost\", :query-string nil, :edn-params {:hello \"there\"}, :scheme :http, :request-method :put}"}
hf.examples> 
我也试过:

(defroutes ajax-example
  (PUT "/ajax-example" r
       {:status 200
        :headers {"Content-Type" "application/edn"}
        :body (pr-str (dissoc r :body))}))
卷曲结果与前端无关:

curl -X PUT -H "Content-Type: application/edn" -d '{:name :barnabas}' http://localhost:6542/ajax-example
{:ssl-client-cert nil, :remote-addr "0:0:0:0:0:0:0:1", :params {}, :route-params {}, :headers {"host" "localhost:6542", "content-length" "17", "content-type" "application/edn", "user-agent" "curl/7.37.1", "accept" "*/*"}, :server-port 6542, :content-length 17, :content-type "application/edn", :character-encoding nil, :uri "/ajax-example", :server-name "localhost", :query-string nil, :edn-params nil, :scheme :http, :request-method

17的
内容长度
与通过Curl传递的映射中的字符数匹配。但是
edn参数
为零!内容在哪里?

编辑:作为对更新问题的回答,wrap edn params函数通过完全读取:body InputStream来消耗请求正文。Compojure将请求传递给每个参数处理程序,直到返回非nil值。在这种情况下,作为第一个处理程序传递给routes的处理程序将使用:body,而第二个处理程序将没有要使用的:body值,这将导致wrap-edn参数读取一个nil body值

传递给环处理程序的请求可能没有将其内容类型设置为edn。仅当请求内容类型设置为edn时,才会解析edn

此外,通过wrap edn params函数,解析的edn参数将仅放置在请求映射的:params和:edn params键中,因此:body不应用于访问解析的edn

(require '[ring.mock.request :as mock])
(require '[ring.middleware.edn :as edn]) 

((-> ajax-example  params/wrap-params edn/wrap-edn-params) (-> (mock/request :put "/ajax-example")
                                                             (mock/content-type "application/edn")
                                                             (mock/body "{:hello \"there\"}"))) 

{:remote-addr "localhost",
 :params {:hello "there"},
 :route-params {},
 :headers
 {"content-length" "16",
  "content-type" "application/edn",
  "host" "localhost"},
 :server-port 80,
 :content-length 16,
 :form-params {},
 :query-params {},
 :content-type "application/edn",
 :uri "/ajax-example",
 :server-name "localhost",
 :query-string nil,
 :body #<ByteArrayInputStream java.io.ByteArrayInputStream@171788d8>,
 :edn-params {:hello "there"},
 :scheme :http,
 :request-method :put}
(需要“[ring.mock.request:as mock]”)
(需要“[ring.middleware.edn:作为edn]”)
((->ajax示例参数/wrap-params-edn/wrap-edn-params)(->(mock/request:put)/ajax示例)
(模拟/内容类型“应用程序/edn”)
(mock/body“{:你好\”there\“}”))
{:远程地址“localhost”,
:params{:hello“there”},
:路由参数{},
:标题
{“内容长度”为“16”,
“内容类型”“应用程序/edn”,
“主机”“本地主机”},
:服务器端口80,
:内容长度16,
:form params{},
:查询参数{},
:内容类型“应用程序/edn”,
:uri“/ajax示例”,
:服务器名称“localhost”,
:查询字符串nil,
:正文#,
:edn params{:hello“there”},
:scheme:http,
:请求方法:put}

我已经解决了这个问题,但我不知道为什么会出现这个问题。我有另一个独立的路线,也包装了EDN中间件。以下是可复制的示例:

(defroutes example-routes2
  (PUT "/test-edn" r
       (println r)
       {:status 200
        :headers {"Content-Type" "application/edn"}
        :body (pr-str (str "request is: " r))}))

(defroutes ajax-example
  (PUT "/ajax-example" r
       (println r)
       {:status 200
        :headers {"Content-Type" "application/edn"}
        :body (pr-str (str "request is: " r))}))

(def edn-routes 
  (-> example-routes2
      edn/wrap-edn-params))

(def ajax-wrapped
  (-> ajax-example
      edn/wrap-edn-params))

;;combining all routes on this page into a single handler
(def example-routes (routes example-routes1  ajax-wrapped edn-routes))
请注意,这两条路由本质上是相同的,并且被相同地包装未能将EDN解析为EDN参数的是
示例路由中第二个列出的路由
def

curl-X PUT-H“内容类型:应用程序/edn”-d'{:name:barnabass}”

返回:

“请求为:{:ssl客户端证书为零,:remote addr\'0:0:0:0:0:1\',:params{},:route params{},:headers{“主机\”“本地主机:6542\”,“内容长度\”“19\”,“内容类型\”“应用程序/edn\”,“用户代理\”“curl/7.37.1\,“接受\”“接受\”“/”,:服务器端口6542,:内容长度19,:内容类型\”“应用程序/edn”\“,:字符编码为nil,:uri \“/test edn\”,:服务器名\“localhost\”,:查询字符串为nil,:body#,:edn参数为nil,:scheme:http,:请求方法:put}”

curl-X PUT-H“内容类型:应用程序/edn”-d'{:name:barnabass}”

返回:

“请求是:{:ssl客户端证书为零,:远程地址为0:0:0:0:0:0:0:1\”,:参数为:{:name:barnabass},:路由参数为:{},:标头为:{“主机”\“本地主机:6542\,“内容长度”\“19\”,“内容类型”\“应用程序/edn\,“用户代理”\“curl/7.37.1\,“接受”\“/”,:服务器端口6542,:内容长度为“应用程序/edn\”,:字符编码为nil,:uri \“/ajax示例\“,:服务器名\“localhost\”,:查询字符串为nil,:body#,:edn参数{:name:barnabass},:scheme:http,:请求方法:put}”


示例路由中切换它们的顺序
切换哪一个有效。谁能解释一下吗?

请求显示了正确的EDN内容类型,我在前端使用cljs ajax使其成为EDN。关于body,我不是直接使用它,而是显示整个请求映射。其中EDN和参数为零。当删除包装器函数并打印主体
(slurp(:body r))
?当我这样做时,它不会打印任何内容。这怎么可能?意味着正文是空的。但同一请求中的内容长度是正确的,显示的长度与我发送的EDN映射中的字符数匹配。您能为您的问题添加相关的客户端代码吗?使用ajax发送方法p对我来说工作正常您是否尝试过使用模拟环调用ajax包装