2
votes

When I try to extract the multipart-params from a POST request like this:

(defroutes upload-routes
  (POST "/upload" {params :params} (println params))

I got {}.

Then I tried like this:

(defroutes upload-routes
  (POST "/upload" {multipart-params :multipart-params} (println multipart-params))

I still got {}.

I guess there are something wrong about my middleware.

So I tried to change the handler, here are the handlers I had tried:

(ns cloudserver.handler
  (:require [compojure.core :refer [defroutes routes]]
            [compojure.route :as route]
            [compojure.handler :as handler]
            [cloudserver.routes.home :refer [home-routes]]
            [noir.util.middleware :as noir-middleware]
            [cloudserver.routes.auth :refer [auth-routes]]
            [cloudserver.routes.upload :refer [upload-routes]]
            [cloudserver.routes.search :refer [search-routes]]
            [cloudserver.routes.download :refer [download-routes]]
            [ring.middleware.defaults :refer [api-defaults wrap-defaults site-defaults]]
            [ring.middleware.multipart-params :refer [wrap-multipart-params]]
            [ring.middleware.params :refer [wrap-params]]
            [noir.session :as session]
            [ring.middleware.session.memory :refer [memory-store]]))


(def app
  (->
   (routes auth-routes
           home-routes
           upload-routes
           search-routes
           download-routes
           app-routes)
   session/wrap-noir-session
   (wrap-defaults(assoc-in site-defaults [:security :anti-forgery] false)
   wrap-multipart-params
   wrap-params))

(def app
  (->
   (routes auth-routes
           home-routes
           upload-routes
           search-routes
           download-routes
           app-routes)
   session/wrap-noir-session
   (wrap-defaults(assoc-in site-defaults [:security :anti-forgery] false)
   wrap-multipart-params))

(def app
  (->
   (routes auth-routes
           home-routes
           upload-routes
           search-routes
           download-routes
           app-routes)
   session/wrap-noir-session
   (wrap-defaults (-> site-defaults
                      (assoc-in [:security :anti-forgery] false)
                      (assoc-in [:params :multipart] true)
                      (assoc-in [:params :nested] true)))
   handler/site))

(def app
  (->
   (routes auth-routes
           home-routes
           upload-routes
           search-routes
           download-routes
           app-routes)
   wrap-multipart-params
   session/wrap-noir-session
   (wrap-defaults(assoc-in site-defaults [:security :anti-forgery] false)))

(def app
  (noir-middleware/app-handler
   [auth-routes
    home-routes
    upload-routes
    search-routes
    download-routes
    app-routes]
   :ring-defaults (assoc site-defaults :security nil)))

But the only result I got is {}


My client code is:

public int upload (String filename, String[] tags, String time, String fingerprint) throws IOException {
    String url = host + "/upload";
    CloseableHttpClient httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build(); 
    HttpPost httpPost =  new HttpPost(url);

    MultipartEntityBuilder mulentity = MultipartEntityBuilder.create();

    mulentity.addBinaryBody("photo", new File(filename));

    for (int i = 0; i < tags.length; i ++) {
        mulentity.addTextBody("tag" + i, tags[i]);
    }

    mulentity.addTextBody("fingerprint", fingerprint);
    mulentity.addTextBody("time", time);
    mulentity.addTextBody("filename", filename.substring(filename.lastIndexOf(File.separatorChar) + 1, filename.length()));

    HttpEntity entity = mulentity.build();
    httpPost.setEntity(entity);
    httpPost.setHeader("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);

    int status = 3;

    try {
        ResponseHandler<String> responseHandler = new BasicResponseHandler();
        String response = httpClient.execute(httpPost, responseHandler);
        status = Integer.parseInt(response);
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } finally {
        httpClient.close();
    }
    return status;

}

I am really a green hand in clojure web programming. Thanks a lot!


Problem sovled. It's because the boundary in the request is wrong.

1

1 Answers

2
votes

I too am "Clojure Green", but in my multipart Ring + Compojure API app, I just destructure the request on the names of the parameters that come in on the multipart request. The one that is actually a temp file gets output by the printf below has a string representation like "#object[java.io.File 0x4blahblahblah". The middleware took care of lifting it out of the request map and making the parameters available by just their names, I think.

(defroutes upload-routes
  (POST "/upload" [photo tag fingerprint time filename :as request]
    (printf
      "photo %s, tag %s, fingerprint %s, time %s, filename %s"
      photo tag fingerprint time filename)))

The :as request isn't really needed if you're not going to do anything with the whole request map. If all you are doing is printf...maybe include it in the printf and you'll get to see a little how the sausage gets made in Ring. Its Maps all the way down.