解析Facebook在Clojure中的签名请求

时间:2014-04-13 21:08:40

标签: facebook clojure leiningen compojure ring

我正在尝试与Luminus建立一个网站,以便学习一些Clojure。我有多年的必要经验,但现在只进入函数式编程。现在,我正在尝试process a signed_request object from Facebook

根据网站我必须:

  1. 在句点(“。”)上拆分字符串并获取2个字符串的向量。
  2. 取第一个字符串,用base64解码并与秘密进行比较。
  3. 取第二个字符串,用base64解码,再用JSON解码。
  4. 如果我使用命令式语言这样做,这真的很直截了当,但在功能方法方面我很无能为力。现在我只知道如何将字符串拆分为2个字符串的向量:

    (defn parse-request [signed_request]
      ((clojure.string/split signed_request #"\.")
        ))
    
    (defn redirect-page [signed_request]
      (layout/render "redirect.html"
                     {:parsed_request parse-request(signed_request)}))
    
    (defroutes home-routes
      (GET "/" [] (home-page))
      (POST "/redirect" [signed_request] (redirect-page signed_request)))
    
    当服务器收到POST请求时,

    重定向页面运行,然后它接受signed_request并将其传递给解析请求函数。解决这个问题的功能方法是什么?

1 个答案:

答案 0 :(得分:1)

我认为你的问题的基本答案是函数式编程更多地是关于输入和输出(考虑数学函数),而命令式编程往往更多地关注副作用和可变数据。而不是思考,"我需要做什么?",思考,"我的目标是什么样的数据结构,以及我如何定义它?"你也可以有副作用(比如打印),但通常你会编写带有参数并返回内容的纯函数。

Destructuring是Clojure中一个非常宝贵的工具,它在这里会派上用场。您希望使用clojure.string/split将字符串拆分为两个字符串,然后使用其中一个字符串和其他字符串执行某些操作。您可以使用let绑定为每个字符串指定名称,如下所示:

(let [[str1 str2] (clojure.string/split signed-request #"\.")]
  (do-stuff-with-str1-and-str2))

我对这个具体问题并不太熟悉,但根据你列出的3个步骤,听起来你会得到2个结果,每个字符串一个。所以,也许你应该专注于编写一个返回包含2个结果的向量的函数,如下所示:

(defn process-signed-request [signed-request]
  (let [[str1 str2] (clojure.string/split signed-request #"\.")]
    [(compare-fn (decode-with-base-64 str1) secret)
     (decode-with-json (decode-with-base-64 str2))]))

请注意,以上是部分伪代码 - 您需要将compare-fndecode-with-base-64decode-with-jsonsecret替换为代表这些内容的实际代码 - 或者你可以保持原样并只是实现这些功能,以便compare-fndecode-with-base-64decode-with-json引用你编写的实际功能。这是函数式编程中的常用方法 - 编写一个简短的高级函数来定义问题的解决方案,然后返回并编写它使用的辅助函数。

顺便说一句,还有其他几种方法可以编写(decode-with-json (decode-with-base-64 str2))部分:

  1. ((comp decode-with-json decode-with-base-64) str2)
  2. (-> str2 decode-with-base-64 decode-with-json)
  3. 我经常发现第二种方法,使用线程宏(->->>),当我知道对象需要做的事情的顺序时,我会想要代码直观地阅读。我觉得它更容易阅读,例如"取str2,用base 64解码,然后用JSON再次解码。"

    另外,这只是一个挑剔的事情,但是当你在Clojure中进行编码时要注意括号的顺序。您现在拥有代码的方式,括号应如下所示:

    (defn parse-request [signed_request]
      (clojure.string/split signed_request #"\."))
    
    (defn redirect-page [signed_request]
      (layout/render "redirect.html"
                     {:parsed_request (parse-request signed_request)}))
    

    如果您有很多必要的经验,那么您可能会在fn(x)语法中根深蒂固地插入,而不是Clojure使用的(fn x) Lisp语法。

    虽然我在挑剔,但在Clojure中使用连字符代替下划线进行符号命名是惯用的。因此,我会将signed_request:parsed_request重命名为signed-request:parsed-request

    希望有所帮助!