2
votes

I am learning Clojure Ring. This is my first handler:

(ns long-hdi.core
 (:gen-class))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (println "Hello, World!"){:body "hello" :status 200})

(defn on-init[](println "Initializing..."))
(defn on-destroy[](println "destroying..."))

This is the project.clj configuration file:

   (defproject long-hdi "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.8.0"]]
  :plugins [[lein-ring "0.9.7"]]
  :ring {:handler long-hdi.core/-main :init long-hdi.core/on-init :destroy long-hdi.core/on-destroy}
  :main ^:skip-aot long-hdi.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})

When I run: lein ring server-headless and browse to http://localhost:3000 I see it prints on the console "Hello, world!" two times. Why does it print 2 times? I suppose it only prints one time only. Then I modify the source code to:

...{:body args :status 200}...

then use Google Chrome to browse to http://localhost:3000 This time, it prints "Hello, world!" 3 times on the console. Why does it change to printing 3 times?

I am using REPL-y 0.3.7, nREPL 0.2.12, Clojure 1.8.0, lein-ring "0.9.7", Windows 10-64 bit.

1
I think want happened is you called -main after you made changes to your code, and the Hello, World!s accumulated on your console.MicSokoli
No, definitely no. I didn't count the accumulated result. Each browser refreshing makes 2 "Hello, world!".Long HDi
Is -main your handler? You're supposed to use other functions as handlers. -main should be used only as the entry point to your application.MicSokoli
Yes, it is the handler. I have just renamed -main to other-functions. Same result.Long HDi
Can you please edit your question, and paste all the code that is in your file.MicSokoli

1 Answers

5
votes

The problem is not happening because of your code, but I will show you below how to modify your code to get the result you want.

To do some more investigation here, open up the Chrome dev tools window (right-click and select "Inspect"). Go to the Network tab at the top. On the left you will see something interesting under the lists of requests: localhost as well as favicon.ico. So, in fact, for each time you reload the browser, it is making a request not only for the page, but for the page icon as well, and that is why you are seeing two requests. Firefox (at least in my case) is just caching the icon after the first load, but chrome is requesting it from the server every time.

So, what can you do about this? Well, every request by the browser calls the same handler. So, you need to next explore routes. This allows you to map a specific browser request to a specific handler. So, you can simply avoid calls to get the favicon. As a tiny working example to get you started, that lets you see the request working in the browser window instead of printing to the command line:

Your project.clj:

(defproject long-hdi "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.8.0"]
                 [ring/ring-core "1.5.1"]
                 [ring/ring-jetty-adapter "1.5.1"]
                 [compojure "1.5.2"]]
  :main long-hdi.core)

And in your main source file:

(ns long-hdi.core
  (:require [ring.adapter.jetty]
            [compojure.core :refer :all]))

(def counter (atom 0))

(defn handler
  [req]
  (swap! counter inc)
  {:body (str "counter is: " @counter) :status 200})

(defroutes app
  (GET "/" [] handler))

(defn -main [& args]
  (ring.adapter.jetty/run-jetty app {:port 3000}))

Run the server, and then open it up in a browser window at localhost:3000:

$ lein run

I hope this helps, and have fun!