如何在环clojure中获取客户端IP地址?

如何在环clojure中获取客户端IP地址?,clojure,ring,Clojure,Ring,当访问者提交表单时,我想关联输入他的IP地址 (POST "/form" {params :params} (assoc params :ip-address the-ip) 如何做到这一点 考虑过这样做: (POST "/form" {params :params client-ip :remote-addr} (->> params keywordize-keys (merge {:ip-address client-ip})

当访问者提交表单时,我想关联输入他的IP地址

(POST "/form" {params :params} (assoc params :ip-address the-ip)
如何做到这一点

考虑过这样做:

(POST "/form" {params    :params
               client-ip :remote-addr} 
      (->> params keywordize-keys (merge {:ip-address client-ip}) str)) 

但是它返回
{…:ip地址“0:0:0:0:0:0:0:1”}

我很确定您可以从ring请求对象获得此信息。看看ring.middleware.dump(句柄转储)包。如果您设置了它并使用了一个简单的路由,您将得到一个很好的网页,其中显示了ring请求对象中提供的所有可用值。非常确定这包括客户端IP地址。由于此信息是从http头中获得的,因此可能比手动将其放入请求参数更可靠—使用表单或json将其放入请求参数可能意味着更容易伪造。此外,如果它已经作为请求对象的一部分随时可用,则意味着您需要做的事情就少了一件。

从Arthur Ulfeldt的评论到Bill的回答,我想我们可以这样写:

(defn get-client-ip [req]
  (if-let [ips (get-in req [:headers "x-forwarded-for"])]
    (-> ips (clojure.string/split #",") first)
    (:remote-addr req)))

从请求对象获取
:remote addr
通常是正确的方法,除非您坐在负载平衡器后面。在这种情况下,负载平衡可能会在请求中添加一个标题,例如
x-forwarded-for
。这将使类似这样的事情变得合适

(or (get-in request [:headers "x-forwarded-for"]) (:remote-addr request))

这是ipv6中的
localhost
。您的请求来自哪里?@cfrick localhost。是 啊我无法在prod中测试这一点,因此无法确定
:remote addr
从您的答案来看,我认为这是正确的。顺便说一句,我刚刚发现我不需要使用关键字fn。只需要
包装关键字参数
。对于本身在代理后面的客户端,这将失败,因为x-forwarded-for将是一个以逗号分隔的IP列表,如“2.2.2.2,5.5.5.5”,实际地址与第一个
之前的所有地址相同,并且请记住,即使您的服务位于IPv4/,它们也可以是IPv6地址,不过,这会返回IPv6地址吗?@Nathanbassanese如果我没有弄错你的问题,我的答案是我没有测试IPv6源。我不知道它是否能正确返回这样一个字符串。。