【问题标题】:Long Response get cuts: clojure.lang.ExceptionInfo: Couldnt' write to stream长响应得到削减:clojure.lang.ExceptionInfo:无法'写入流
【发布时间】:2017-05-19 16:55:15
【问题描述】:

我将以下代码添加到一个干净的Luminus 并遇到了以下问题:

如果我请求的 API 响应 100 KB(可能或更多)数据,那么长响应将被截断,因此我只能获得其中的一部分。

我不确定这是否是因为以下代码。我不熟悉JAVA,您能给我一些建议吗?我正在使用Luminus框架,相关代码是:

(def app-routes
  (routes
   (-> #'home-routes
       (wrap-routes middleware/wrap-csrf)
       (wrap-routes middleware/wrap-formats)
       )
   (->
    (route/not-found
     (:body
      (error-page {:status 404
                   :title "page not found"})))
    middleware/wrap-proxy)))

(defn app [] (middleware/wrap-base #'app-routes))

(defn create-proxy [handler fns]
  (let [identifier-fn (get fns :identifier-fn identity)
        host-fn (get fns :host-fn {})
        path-fn (get fns :path-fn identity)]
    (fn [request]
      (let [request-key (identifier-fn request)
            host (host-fn request-key)
            stripped-headers (dissoc (:headers request) "content-length" "host")
            path (path-fn (:uri request))
            ]
        (if host
          (->
           {:url              (build-url host (path-fn (:uri request)) (:query-string request))
            :method           (:request-method request)
            :body             (if-let [len (get-in request [:headers "content-length"])]
                                (slurp-binary
                                 (:body request)
                                 (Integer/parseInt len)))
            :headers          stripped-headers
            :follow-redirects true
            :throw-exceptions false
            :as               :stream
            :insecure?        true
            }
           client/request
           (update-in [:headers] dissoc "Transfer-Encoding")
           prepare-cookies
           )
          (handler request))))))


(defn wrap-proxy [handler]
  (-> handler
      (create-proxy
       {:identifier-fn :uri
        :host-fn (fn [^String uri]
                   (cond
                     ;; (.startsWith uri "/www") "http://localhost:6787/p/www/stockinfogate"
                     (.startsWith uri "/www") "https://m.joudou.com/p/www/stockinfogate"
                     (.startsWith uri "/beta") "https://m.joudou.com/p/beta/stockinfogate"
                     :else nil))
        :path-fn (fn [^String uri] (s/join "/" (cons "" (drop 2 (s/split uri #"/")))))})))

截取响应数据的url: http://localhost:3000/www/stock/klinedata?stockid=300370.SZ&period=D

原始网址: https://www.joudou.com/stockinfogate/stock/klinedata?stockid=300370.SZ&period=D

错误信息是:

2017-05-20 00:19:02,287 [qtp1106269094-16] WARN  org.eclipse.jetty.server.HttpChannel - //localhost:3000/www/stock/klinedata?stockid=300370.SZ&period=D
clojure.lang.ExceptionInfo: Couldnt' write to stream
    at clojure.core$ex_info.invokeStatic(core.clj:4617)
    at clojure.core$ex_info.invoke(core.clj:4617)
    at qbits.jet.servlet$write_stream_BANG_.invokeStatic(servlet.clj:131)
    at qbits.jet.servlet$write_stream_BANG_.invoke(servlet.clj:126)
    at qbits.jet.servlet$eval37883$fn__37884.invoke(servlet.clj:153)
    at qbits.jet.servlet$eval37796$fn__37797$G__37787__37806.invoke(servlet.clj:88)
    at qbits.jet.servlet$set_response_body_BANG_.invokeStatic(servlet.clj:93)
    at qbits.jet.servlet$set_response_body_BANG_.invoke(servlet.clj:91)
    at qbits.jet.servlet$set_body_BANG_.invokeStatic(servlet.clj:229)
    at qbits.jet.servlet$set_body_BANG_.invoke(servlet.clj:220)
    at qbits.jet.servlet$eval38053$fn__38054.invoke(servlet.clj:263)
    at qbits.jet.servlet$eval38024$fn__38025$G__38015__38032.invoke(servlet.clj:236)
    at qbits.jet.servlet$update_response.invokeStatic(servlet.clj:241)
    at qbits.jet.servlet$update_response.invoke(servlet.clj:239)
    at qbits.jet.server$make_handler$fn__38414.invoke(server.clj:78)
    at qbits.jet.server.proxy$org.eclipse.jetty.server.handler.AbstractHandler$ff19274a.handle(Unknown Source)
    at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:52)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:134)
    at org.eclipse.jetty.server.Server.handle(Server.java:518)
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:308)
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:244)
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:273)
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:95)
    at org.eclipse.jetty.io.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:93)
    at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceAndRun(ExecuteProduceConsume.java:246)
    at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:156)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:654)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:572)
    at java.lang.Thread.run(Thread.java:745)

我丢了一个slurp-binary,我试过这个功能的两个版本,一个是

(defn slurp-binary
  "Reads len bytes from InputStream is and returns a byte array."
  [^java.io.InputStream is len]
  (with-open [rdr is]
    (let [buf (byte-array len)]
      (.read rdr buf)
      buf)))

另一个是:

 (defn slurp-binary
    "Reads len bytes from InputStream is and returns a byte array."
    [^java.io.InputStream is len]
  (when (and is
             (> len 0))
    (with-open [rdr is]
      (let [buf (byte-array len)]
        (.read rdr buf)
        buf))))

我不确定函数是错误发生的地方,但两个版本都不起作用。

谢谢。


我试图获取原始请求和client/request 请求,然后我在 REPL 中得到了完整的响应。所以我怀疑是wrap-base导致响应被切断。

【问题讨论】:

    标签: clojure luminus


    【解决方案1】:

    这是什么slurp-binary?它似乎在做所有重要的工作,但不是我所知道的任何常用库的一部分。

    谷歌搜索表明您可能正在使用https://crossclj.info/ns/com.guaranteedrate/ring-proxy/3.0.0/tailrecursion.ring-proxy.html#_slurp-binary,这是一个乍一看显然不正确的函数。我可以想象它会导致像你看到的那样的错误,但我不确定。在那里我还看到了一个与你的函数体非常相似的wrap-proxy 函数:你是写了这两个,还是复制了它们,还是什么?

    无论如何,slurp-binary 显然是问题的重要组成部分,如果不知道发生了什么,我们无法真正回答您的问题。

    【讨论】:

    • 嗨,我从 github 的两个 repos 中复制了:tailrecursion/ring-proxyhttps://github.com/FundingCircle/ring-request-proxy,并进行了一些小改动。我将使用slurp-binary 更新问题。我认为slurp-binaryrequest 相关而不是response,所以我也不确定slurp-binary 的作用以及inputstreamrequest 还是response 的主体。我还发现了 github.com/mhjort/ring-apigw-lambda-proxy/blob/master/src/ring/… 。在这里,他使用了 ByteArrayInputStream。这做同样的工作吗?谢谢。
    猜你喜欢
    • 1970-01-01
    • 2017-07-14
    • 2018-01-10
    • 2015-04-01
    • 2011-08-15
    • 2019-11-11
    • 2015-11-18
    • 1970-01-01
    相关资源
    最近更新 更多