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

时间:2015-05-13 08:40:39

标签: clojure ring

我认为我做得对,但我无法从:body输入流中获取我的EDN。 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-client-cert nil,:remote-addr 0:0:0:0:0:0:0:1,:params {} ,: route-params {} ,: headers {origin {{ 3}},主机localhost: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; content-length 20,referer http://localhost:6542,connection keep-alive,accept / ,accept-language en-US,en; q = 0.8,sq; q = 0.6,accept-encoding gzip ,deflate,sdch,cache-control max-age = 0} ,: server-port 6542,:content-length 20,:form-params {} ,: query-params {} ,: 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的content-length匹配通过Curl传递的地图中的字符数。但是edn-params是零!内容在哪里?

2 个答案:

答案 0 :(得分:3)

编辑:作为更新问题的答案,wrap-edn-params函数通过完全读取:body InputStream来消耗请求的主体。 Compojure路由将请求传递给每个参数处理程序,直到返回非nil值。在这种情况下,无论哪个处理程序传递给路由,因为第一个处理程序将使用:body,并且第二个处理程序将不会使用:body值,导致wrap-edn-params读取nil正文值。

传递给环处理程序的请求可能没有将其content-type设置为edn。如果请求内容类型设置为edn,wrap-edn-params function将仅解析edn。

此外,解析的edn参数将仅通过wrap-edn-params函数放置在请求映射的: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}

答案 1 :(得分:0)

我已修复此问题,但我不知道问题存在的原因。我有另一条独立的路线,也包裹着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-params的那个是example-routes def中列出的第二个

卷曲-X PUT -H&#34;内容类型:application / edn&#34; -d&#39; {:name:barnabasss}&#39; http://localhost:6542/test-edn

返回:

&#34;请求是:{:ssl-client-cert nil,:remote-addr \&#34; 0:0:0:0:0:0:0:1 \&#34;,: params {},:route-params {} ,: headers {\&#34; host \&#34; \&#34; localhost:6542 \&#34;,\&#34; content-length \&#34; \&#34; 19 \&#34;,\&#34;内容类型\&#34; \&#34; application / edn \&#34;,\&#34; user-agent \&#34; \&#34; curl / 7.37.1 \&#34;,\&#34;接受\&#34; \&#34; / \&#34;} ,: server-port 6542,:content-length 19,:content-type \&#34; application / edn \&#34;, :字符编码nil,:uri \&#34; / test-edn \&#34;,:server-name \&#34; localhost \&#34; ,: query-string nil,:body#,< strong>:edn-params nil,:scheme:http,:request-method:put}&#34;

卷曲-X PUT -H&#34;内容类型:application / edn&#34; -d&#39; {:name:barnabasss}&#39; http://localhost:6542/ajax-example

返回:

&#34;请求是:{:ssl-client-cert nil,:remote-addr \&#34; 0:0:0:0:0:0:0:1 \&#34;,: params {:name:barnabasss} ,: route-params {} ,: headers {\&#34; host \&#34; \&#34; localhost:6542 \&#34;,\&#34; content-length \&#34; \&#34; 19 \&#34;,\&#34;内容类型\&#34; \&#34; application / edn \&#34;,\&#34; user-agent \&#34; \&#34; curl / 7.37.1 \&#34;,\&#34;接受\&#34; \&#34; / \&#34;} ,: server-port 6542,:content-length 19,:content-type \&#34; application / edn \&#34;, :字符编码nil,:uri \&#34; / ajax-example \&#34;,:server-name \&#34; localhost \&#34; ,: query-string nil,:body#,< strong>:edn-params {:name:barnabasss},:scheme:http,:request-method:put}&#34;

example-routes开关中切换它们的顺序。谁能解释一下?