在实时站点上通过 Golang 连接到云 SQL (MySQL)

Connecting to Cloud SQL (MySQL) through Golang on a live site

我目前有一个初始页面,运行 通过 Google 的 App Engine。截至目前,它只是一个页面,要求用户提供他们的电子邮件和姓名,以建立电子邮件列表。我想将信息存储在云 sql 上,但我似乎无法让它在实时站点上运行。截至目前,我正在使用 MySQLWorkbench 成功连接到云上的数据库 sql 并且我可以输入数据并提交它,成功地将信息填充到云上的数据库中。我没有收到任何连接错误,它在 localhost:8080/ 上按预期在本地工作。然后我将我的更改部署到 App Engine 并导航到该站点,填写信息,然后点击提交页面挂起,最终 returns 我的 Insert 方法出现 500 错误。这是我第一次在实时站点上使用数据库,所以我无法理解从本地主机转移到实时站点的问题是什么。

main.go:


import (
    "database/sql"
    "fmt"
    "html/template"
    "log"
    "net/http"
    "os"
    "path/filepath"
    "strings"

    _ "github.com/go-sql-driver/mysql"
)

// Page type
type Page struct {
    Title string
}

type emailListUser struct {
    ID    int
    Name  string
    email string
}

// Connect to DB
func dbConn() (db *sql.DB) {
    dbDriver := "mysql"
    dbUser := "jmcarthur"
    dbPass := "my_password"
    dbName := "tcp(ipFromGoogle:port)/tableName" // Also tried ipFromGoogle:port and ipFromGoogle

    db, err := sql.Open(dbDriver, dbUser+":"+dbPass+"@"+dbName)
    if err != nil {
        log.Println("Failed connection")
    }

    return db
}

// Handlers
func emailListHandler(w http.ResponseWriter, r *http.Request) {
    tpl.ExecuteTemplate(w, "emailList", &Page{Title: "Welcome to My Site"})
}

func main() {
    http.HandleFunc("/", emailListHandler)
    http.HandleFunc("/insert", Insert)
    fs := http.FileServer(http.Dir("static"))
    http.Handle("/css/", fs)
    http.Handle("/fonts/", fs)
    http.Handle("/img/", fs)
    http.Handle("/templates/", fs)

    fmt.Println(http.ListenAndServe(":8080", nil))
}

var tpl = func() *template.Template {
    t := template.New("")
    err := filepath.Walk("./", func(path string, info os.FileInfo, err error) error {
        if strings.Contains(path, ".html") {
            fmt.Println(path)
            _, err = t.ParseFiles(path)
            if err != nil {
                fmt.Println(err)
            }
        }
        return err
    })

    if err != nil {
        panic(err)
    }
    return t
}()

// Insert function
func Insert(w http.ResponseWriter, r *http.Request) {
    db := dbConn()

    if r.Method == "POST" {
        email := r.FormValue("email")
        name := r.FormValue("name")

        insForm, err := db.Prepare("INSERT INTO emailList(email_address, name) VALUES(?,?)")
        if err != nil {
            panic(err.Error())
        }

        insForm.Exec(email, name)
        log.Println("INSERT: Email: " + email + " | Name: " + name)
    }

    defer db.Close()
    http.Redirect(w, r, "/", 301)
}

/* CREATE TABLE tableName(
    email_id INT NOT NULL AUTO_INCREMENT,
    email_address VARCHAR(320) NOT NULL,
    name VARCHAR(150) NOT NULL,
    PRIMARY KEY (email_id)
); */

emailList.html

{{define "emailList"}}
<!DOCTYPE html>
<html lang="en">
    {{template "header" .}}
    <body id="emailListBody" class="text-center">
        <div id="emailListContainer" class="col-12 text-center">
            <img src="./img/picture.png" height="250px" width="250px">
            <h1 class="text-center" id="slogan">slogan</h1>
            <div id="formDiv" class="text-center">
                <form method="POST" action="insert">
                    <label for="email" class="col-12" id="emailLabel">Email:</label>
                    <input type="email" required placeholder="johndoe@email.com" id="email" name="email">
                    <label for="name" class="col-12" id="nameLabel">Name:</label>
                    <input type="text" required placeholder="John Doe" id="name" name="name">
                    <div class="col">
                        <button class="btn btn-default" id="submitButton">SUBMIT</button>
                    </div>
                </form>
            </div>
        </div>
    {{template "footer" .}}
{{end}}

树:

.
├── app.yaml
├── cloud_sql_proxy
├── main.go
└── static
    ├── css
    │   └── main.css
    ├── emailList.html
    ├── fonts
    │   ├── EuroStyle\ Normal.ttf
    │   ├── EurostileBold.ttf
    │   └── ethnocentric\ rg.ttf
    ├── img
    │   ├── picture.png
    ├── js
    └── templates
        ├── footer.html
        └── header.html

正如我所说,我可以成功地让它在本地运行,但我终究无法让它在实时站点上运行。我已确保我的 IP 已列入白名单,我尝试以多种不同的方式连接 IP,使用和不使用端口(如 main.go 中所示),但每次我都得到 POST mysite [HTTP/2 500 Internal Server Error 1857ms]。我相信我对云 sql 和允许任何 IP 将数据发送到数据库感到困惑,但我可能完全错了。请帮忙,谢谢!!

如果问题不在于您的连接字符串,则 App Engine 的过程有更多问题,例如 permissions for standard or permissions for Flex。

您的 /table 变量 dbName 中的名称字符串似乎也表示 table 名称?看this例子,有和instance + dbname,没有table。实例是一组数据库名称。但是,如果您的代码在具有相同配置的本地云 SQL 上运行,则忽略此部分并仅查看权限。

可能性太多了。请使用 public Google 文档作为测试进一步隔离。

问题出在我的连接功能上。最终有效的解决方案如下所示。

Note: projectID = name of your google cloud project
      cloudSQLInstace = name of the instance you created for cloud SQL
      my_username and my_password come from created user under SQL -> Users
func dbConn() (db *sql.DB) {
    dbDriver := "mysql"
    dbUser := "my_username"
    dbPass := "my_password"
    dbInstance := "projectID:us-central1:cloudSQLInstace"
    dbName := "emailList"

    db, err := sql.Open(dbDriver, dbUser+":"+dbPass+"@unix(/cloudsql/"+dbInstance+")/"+dbName)
    if err != nil {
        log.Fatalf("Failed connection")
    }

    return db
}