在实时站点上通过 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
}
我目前有一个初始页面,运行 通过 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
}