【问题标题】:In GoLang How do I get the HandleFunc() function to parse a json into variables accesible outside of the function在 GoLang 中,如何让 HandleFunc() 函数将 json 解析为函数外部可访问的变量
【发布时间】:2017-01-25 14:42:45
【问题描述】:

我正在尝试使用 golang 创建一个服务,该服务将在端口上侦听包含 json 的 post 请求,并希望解析 json 的用户名和密码字段并将它们保存为要在函数外部使用的变量向 Active Directory 进行身份验证。 我正在使用 HandleFunc() 函数,但无法弄清楚如何访问函数外部的变量。我尝试创建一个回报,但它不会建立。如何正确创建变量,然后在函数外部使用它们?

 package main

 import (
         "gopkg.in/ldap.v2"
         "fmt"
         "net/http"
         "os"
         "encoding/json"
         "log"
         "crypto/tls"
         "html"

 )

 type Message struct {
     User string 
     Password string 
 }

 func main() {
     const SERVICE_PORT = "8080"


     var uname string
     var pwd string

     LDAP_SERVER_DOMAIN := os.Getenv("LDAP_DOM")
     if LDAP_SERVER_DOMAIN == "" {
        LDAP_SERVER_DOMAIN = "192.168.10.0" 
     }


     //Handle Http request and parse json
     http.HandleFunc("/", func(w http.ResponseWriter, request *http.Request) {
            var m Message

            if request.Body == nil {
            http.Error(w, "Please send a request body", 400)                
            return
            }

            err := json.NewDecoder(request.Body).Decode(&m)
            if err != nil {
                http.Error(w, err.Error(), 400)
                return
            }
            // Not sure what to do here
            uname = m.User
            pwd = m.Password
        })

     log.Fatal(http.ListenAndServe(":" + SERVICE_PORT, nil))

     connected := ldapConn(LDAP_SERVER_DOMAIN, uname, pwd)

     if connected == true {
        fmt.Println("Connected is", connected)
     }


 }


// Connects to the ldap server and returns true if successful
 func ldapConn(dom, user, pass string) bool {
    // For testing go insecure
    tlsConfig := &tls.Config{InsecureSkipVerify: true}

    conn, err := ldap.DialTLS("tcp", dom, tlsConfig)
    if err != nil {
        // error in connection
        log.Println("ldap.DialTLS ERROR:", err)

        //debug
        fmt.Println("Error", err)

        return false
    }
    defer conn.Close()
    err = conn.Bind(user, pass)
    if err != nil {
        // error in ldap bind
        log.Println(err)

        //debug
        log.Println("conn.Bind ERROR:", err)

        return false
    }
    return true
}

【问题讨论】:

  • 由于几个原因,这没有意义。 ldapConn 函数将在您的处理程序之前被调用,因此不会设置这些变量。这也没有尝试考虑并发调用处理程序时会发生什么。只需声明变量并在处理程序中调用 auth 函数。你也没有 http 服务器,所以没有什么可以调用你的处理程序,你的程序就退出了。
  • 我只是在本地主机上收听。当我使用 json 卷曲本地主机时,我的处理程序可以很好地接收它。我似乎无法在处理程序中调用任何函数。当我尝试一个简单的 fmt.PrintLn 时,我在控制台中什么也得不到。
  • 抱歉,我错过了 ListenAndServe,所以你有一个 http 服务器,所以你永远不会接到 ldapConn 电话,因为你在那里被阻塞了。函数调用在处理程序中的工作方式与其他任何地方完全相同,您必须展示一个不适合您的示例。
  • 我真的开始允许 fmt.Println() 进入处理程序。 Grrrr....好吧。我将把我的函数调用移到处理程序内部的 LDAP 并立即尝试。
  • 确保在处理程序中移动相关的变量声明以避免竞争条件。

标签: json go active-directory ldap httphandler


【解决方案1】:

您不能访问变量不是因为 Go 命名空间不允许,而是因为 ListenAndServe 是阻塞的,并且只有在服务器停止时才能调用 ldapConn

 log.Fatal(http.ListenAndServe(":" + SERVICE_PORT, nil))
 // Blocked until the server is listening and serving.

 connected := ldapConn(LDAP_SERVER_DOMAIN, uname, pwd)

更正确的方法是在http.HandleFunc 回调中调用ldapConn

 http.HandleFunc("/", func(w http.ResponseWriter, request *http.Request) {
        var m Message

        if request.Body == nil {
            http.Error(w, "Please send a request body", 400)                
            return
        }

        err := json.NewDecoder(request.Body).Decode(&m)
        if err != nil {
            http.Error(w, err.Error(), 400)
            return
        }

        connected := ldapConn(LDAP_SERVER_DOMAIN, m.User, m.Password)
        if connected == true {
            fmt.Println("Connected is", connected)
        }
 })

 log.Fatal(http.ListenAndServe(":" + SERVICE_PORT, nil))

【讨论】:

    【解决方案2】:

    如何让 HandleFunc() 函数将 json 解析为变量 可以在函数之外访问吗?

    根据您的问题,我认为您不能在此处返回 json 值。相反,您可以将结构传递给函数并在其中调用它们。 例如:

    //Handle Http request and parse json
         http.HandleFunc("/", func(w http.ResponseWriter, request *http.Request) {
                var m Message
    
                if request.Body == nil {
                http.Error(w, "Please send a request body", 400)                
                return
                }
    
                err := json.NewDecoder(request.Body).Decode(&m)
                if err != nil {
                    http.Error(w, err.Error(), 400)
                    return
                }
                // Not sure what to do here
                // pass the variable to your function
                uname = m.User
                pwd = m.Password
    
                // passed your struct to a function here and do your logic there.
                yourFunction(m)
            })
    

    并且您可以将yourFunction(m Message) 写入另一个包或与您定义处理程序相同的包中。例如写yourFunction() 将是:

    func yourFunction(m Message){
       // do your logic here
    }
    

    如果函数在另一个包中

    //call your package where your struct is defined.
    func yourFunction(m main.Message){
       // do your logic here
    }
    

    正如JimB 所说。你在ListenAndServe 之后调用你的ldapConn,这些行将永远不会被执行,因为它被阻止了。

    如果您想打印您的应用程序已启动或失败。我认为这段代码会对你有所帮助:

        log.Println("App started on port = ", port)
        err := http.ListenAndServe(":"+port, nil)
        if err != nil {
            log.Panic("App Failed to start on = ", port, " Error : ", err.Error())
        }
    

    【讨论】:

    • 所有 http 处理程序本质上都是并发的。如果没有从 http 处理程序中同步,您将无法访问全局变量。
    • @JimB 抱歉,我已经编辑了我的答案,因为对我来说真的太晚了,所以我没有太多时间来编辑它。是的,这是一个错误
    猜你喜欢
    • 2020-04-26
    • 2017-06-01
    • 2020-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-25
    相关资源
    最近更新 更多