无法在此服务器请求中解析出 EDN
Unable to parse out EDN in this server request
我认为我做的事情是正确的,但我无法从 :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
的回复正确显示是EDN,内容长度是正确的,但地图本身无处可寻,永远被困在 :body
的输入流中...如何获取?
这是响应 println:
{:ssl-client-cert nil, :remote-addr 0:0:0:0:0:0:0:1, :params {}, :route-params {}, :headers {origin http://localhost:6542, host localhost:6542, user-agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36, content-type application/edn, cookie _ga=GA1.1.1354518981.1429622648; content-length 20, referer http://localhost:6542/, connection keep-alive , 接受 /, 接受语言 en-US,en;q=0.8,sq;q=0.6, 接受编码 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}
上面的 :body 粘贴不正确,看起来像这样:
[open corner bracket] HttpInput org.eclipse.jetty.server.HttpInput@5d969109 [end corner bracket]
使用cljs-ajax
库从浏览器发送的客户端代码是:
(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
是零!内容在哪里?
编辑:作为更新问题的答案,wrap-edn-params 函数通过完全读取 :body InputStream 来消耗请求的主体。 Compojure 路由将请求传递给每个参数处理程序,直到返回非 nil 值。在这种情况下,无论哪个处理程序作为第一个处理程序传递给路由,都将使用 :body 并且不会有 :body 值供第二个处理程序使用,导致 wrap-edn-params 读取 nil body 值。
传递给环处理程序的请求可能没有将其内容类型设置为 edn。如果请求内容类型设置为 edn,wrap-edn-params function 将仅解析 edn。
另外解析后的edn参数只会被wrap-edn-params函数放在request map的:params和:edn-params键中,因此:body不应该用来访问解析后的参数编辑
(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}
我已经解决了这个问题,但我不知道为什么会出现这个问题。我有另一个独立的路线,也包装了 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!
中第二个列出的那个
curl -X PUT -H "Content-Type: application/edn" -d '{:name :barnabasss}' http://localhost:6542/test-edn
returns:
"request is: {:ssl-client-cert nil, :remote-addr \"0:0:0:0:0:0:0:1\", :params {}, :route-params {}, :headers {\"host\" \ "localhost:6542\", \"content-length\" \"19\", \"content-type\" \"application/edn\", \"user-agent\" \"curl/7.37.1\", \"accept\" \"/\"}, :server-port 6542, :content-length 19, :content-type \"application/edn\", :character-encoding nil, :uri \" /test-edn\", :server-name \"localhost\", :query-string nil, :body #, :edn-params nil, :scheme :http, :请求方法:put}"
curl -X PUT -H "Content-Type: application/edn" -d '{:name :barnabasss}' http://localhost:6542/ajax-example
returns:
"request is: {:ssl-client-cert nil, :remote-addr \"0:0:0:0:0:0:0:1\", :params {:name :barnabasss}, :route-params {}, :headers {\"host\" \"localhost:6542\", \"content-length\" \"19\", \"content-type\" \"application/edn\", \"user-agent\" \"curl/7.37.1\", \"accept\" \"/\"}, :server-port 6542, :content-length 19, :content-type \"application/edn\", :character-encoding nil, :uri \"/ajax-example\", :server-name \"localhost\", :query-string nil, :body #, :edn-params {:name :barnabasss }, :scheme :http, :request-method :put}"
在 example-routes
中切换它们的顺序会切换哪个有效。谁能解释一下?
我认为我做的事情是正确的,但我无法从 :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
的回复正确显示是EDN,内容长度是正确的,但地图本身无处可寻,永远被困在 :body
的输入流中...如何获取?
这是响应 println:
{:ssl-client-cert nil, :remote-addr 0:0:0:0:0:0:0:1, :params {}, :route-params {}, :headers {origin http://localhost:6542, host localhost:6542, user-agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36, content-type application/edn, cookie _ga=GA1.1.1354518981.1429622648; content-length 20, referer http://localhost:6542/, connection keep-alive , 接受 /, 接受语言 en-US,en;q=0.8,sq;q=0.6, 接受编码 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}
上面的 :body 粘贴不正确,看起来像这样:
[open corner bracket] HttpInput org.eclipse.jetty.server.HttpInput@5d969109 [end corner bracket]
使用cljs-ajax
库从浏览器发送的客户端代码是:
(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
是零!内容在哪里?
编辑:作为更新问题的答案,wrap-edn-params 函数通过完全读取 :body InputStream 来消耗请求的主体。 Compojure 路由将请求传递给每个参数处理程序,直到返回非 nil 值。在这种情况下,无论哪个处理程序作为第一个处理程序传递给路由,都将使用 :body 并且不会有 :body 值供第二个处理程序使用,导致 wrap-edn-params 读取 nil body 值。
传递给环处理程序的请求可能没有将其内容类型设置为 edn。如果请求内容类型设置为 edn,wrap-edn-params function 将仅解析 edn。
另外解析后的edn参数只会被wrap-edn-params函数放在request map的:params和:edn-params键中,因此:body不应该用来访问解析后的参数编辑
(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}
我已经解决了这个问题,但我不知道为什么会出现这个问题。我有另一个独立的路线,也包装了 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!
curl -X PUT -H "Content-Type: application/edn" -d '{:name :barnabasss}' http://localhost:6542/test-edn
returns:
"request is: {:ssl-client-cert nil, :remote-addr \"0:0:0:0:0:0:0:1\", :params {}, :route-params {}, :headers {\"host\" \ "localhost:6542\", \"content-length\" \"19\", \"content-type\" \"application/edn\", \"user-agent\" \"curl/7.37.1\", \"accept\" \"/\"}, :server-port 6542, :content-length 19, :content-type \"application/edn\", :character-encoding nil, :uri \" /test-edn\", :server-name \"localhost\", :query-string nil, :body #, :edn-params nil, :scheme :http, :请求方法:put}"
curl -X PUT -H "Content-Type: application/edn" -d '{:name :barnabasss}' http://localhost:6542/ajax-example
returns:
"request is: {:ssl-client-cert nil, :remote-addr \"0:0:0:0:0:0:0:1\", :params {:name :barnabasss}, :route-params {}, :headers {\"host\" \"localhost:6542\", \"content-length\" \"19\", \"content-type\" \"application/edn\", \"user-agent\" \"curl/7.37.1\", \"accept\" \"/\"}, :server-port 6542, :content-length 19, :content-type \"application/edn\", :character-encoding nil, :uri \"/ajax-example\", :server-name \"localhost\", :query-string nil, :body #, :edn-params {:name :barnabasss }, :scheme :http, :request-method :put}"
在 example-routes
中切换它们的顺序会切换哪个有效。谁能解释一下?