Go GAE应用在本地运行正常,但部署后出现404/无内容的错误。

huangapple go评论91阅读模式
英文:

Go GAE app works locally, when deployed I get 404/nothing

问题

我正在处理一个 PartyCon 项目的服务器端部分。它使用 Golang 在 Google App Engine 平台上编写。我刚刚实现了一些在本地完美运行的新功能。然而,当部署后,我无法访问 console.go 脚本。

这是我的 app.yaml 配置(抱歉,这是 stackoverflow 显示 yaml 文件的方式):

application: party-serverside
version: alpha-1
runtime: go
api_version: go1

handlers:
  #handlers for api
  - url: /api/.*
    script: api/api.go

  #handlers for console and webpage routing
  - url: /redirect
    script: redirecter/redirecter.go

  - url: /admin_console/choose
    script: admin_console/choose.go

  - url: /post-request
    script: webpage/post-request.go

  - url: /console
    script: console/console.go

  #handlers for static files
  - url: /css/console.css
    static_files: console/page/css/console.css
    upload: console/page/css/console.css

  - url: /console/page
    static_dir: console/page

  - url: /
    static_files: webpage/index.html
    upload: webpage/index.html

  - url: /
    static_dir: webpage

  - url: /css
    static_dir: webpage/css

  - url: /js
    static_dir: webpage/js

  - url: /img
    static_dir: webpage/img

  - url: /fonts
    static_dir: webpage/fonts

这是我的 console.go 文件:

package console

import (
	"appengine"
	"appengine/user"
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"html/template"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"
)

//for deployment
var dbConnectString string = "****************************"

//for local testing
//var dbConnectString string = "root@/party"

func init() {
	http.HandleFunc("/console", consoleHandler)
}

func consoleHandler(w http.ResponseWriter, r *http.Request) {
	redirectIfNeeded(w, r)
	c := appengine.NewContext(r)
	u := user.Current(c)

	logoutUrl, e := user.LogoutURL(c, "/redirect")

	if e != nil {
		panic(e)
	}

	email := u.Email
	data := WebpageData{LogoutUrl: logoutUrl, UserName: email, NewPartyUrl: "/console/newparty"}

	template := template.Must(template.New("template").Parse(generateUnsignedHtml(u)))

	err := template.Execute(w, data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}

func generateUnsignedHtml(u *user.User) string {
	firstPart := fileValue("./console/page/firstPart.html")
	table := generateTable(u)
	secondPart := fileValue("./console/page/secondPart.html")

	html := firstPart + table + secondPart
	return html
}

func generateTable(u *user.User) string {
	con, e := sql.Open("mysql", dbConnectString)
	if e != nil {
		panic(e)
	}
	defer con.Close()

	var parties []Party
	partyRows, err := con.Query("select id, name, datetime, host, location from parties where author='" + u.Email + "';")
	if err != nil {
		panic(err)
	}

	var id int
	var name string
	var datetime string
	var host string
	var location string

	for partyRows.Next() {
		partyRows.Scan(&id, &name, &datetime, &host, &location)
		parties = append(parties, Party{Id: id, Name: name, DatetimeString: datetime, Host: host, Location: location})
	}

	html := ""
	for i, party := range parties {
		actionsHtml := "<a href=\"/console/edit?id=" + strconv.Itoa(party.Id) + "\" class=\"uk-button uk-button-primary editButton\">Edit</a> <a href=\"/console/delete?id=" + strconv.Itoa(party.Id) + "\" class=\"uk-button uk-button-danger\">Delete</a>"
		html += "<tr>" + makeTd(strconv.Itoa(i+1)) + makeTd(party.Name) + makeTd(party.DatetimeString) + makeTd(party.Host) + makeTd(party.Location) + makeTd(actionsHtml) + "</tr>"
	}

	html += "</table>"
	return html
}

func makeTd(content string) string {
	return "<td>" + content + "</td>"
}

func redirectIfNeeded(w http.ResponseWriter, r *http.Request) {
	expire := time.Date(2000, 1, 1, 1, 1, 1, 0, time.UTC)
	cookie := &http.Cookie{Name: "ACSID", Value: "", Expires: expire, HttpOnly: true}
	http.SetCookie(w, cookie)
	cookie2 := &http.Cookie{Name: "SACSID", Value: "", Expires: expire, HttpOnly: true}
	http.SetCookie(w, cookie2)

	c := appengine.NewContext(r)
	u := user.Current(c)
	if u == nil {
		url, err := user.LoginURL(c, r.URL.String())
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Header().Set("Location", url)
		w.WriteHeader(http.StatusFound)
		return
	}

	con, e := sql.Open("mysql", dbConnectString)
	if e != nil {
		panic(e)
	}
	defer con.Close()

	//check whether user is admin
	admRows, error := con.Query("select email from admin_users;")
	if error != nil {
		panic(error)
	}
	var email string
	isAdmin := false
	for admRows.Next() {
		admRows.Scan(&email)
		if email == u.Email {
			isAdmin = true
		}
	}

	//check if he is validated user
	validRows, error2 := con.Query("select email from party_validated_users;")
	if error2 != nil {
		panic(error2)
	}
	email = ""
	isValidated := false
	for validRows.Next() {
		validRows.Scan(&email)
		if email == u.Email {
			isValidated = true
		}
	}

	var url string

	if user.IsAdmin(c) || isAdmin {
		//user is declared as admin in db or is admin of gae app
		//we are allready here
		url = "/console"
	} else if isValidated {
		//user is validated
		//we are allready here
		url = "/console"
	} else {
		//user is not validated yet
		url = "/redirect"
		w.Header().Set("Location", url)
		w.WriteHeader(http.StatusFound)
	}
}

func fileValue(path string) string {
	content, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}
	return string(content)
}

type WebpageData struct {
	LogoutUrl   string
	UserName    string
	NewPartyUrl string
}

type Party struct {
	Id             int
	Name           string
	DatetimeString string
	Host           string
	Location       string
}

有什么想法为什么会发生这种情况吗?提前感谢你的帮助!

英文:

I'm working on a serverside part of a PartyCon project. It is written in Golang on Google App Engine platform. I have just implemented a few new things which work perfectly LOCALLY. However, when deployed, I cannot rich console.go script.

Here is my app.yaml configuration (sorry, this is how stackoverflow shows yaml files):

application: party-serverside version: alpha-1 runtime: go
api_version: go1
handlers:
#handlers for api
- url: /api/.*   
script: api/api.go
#handlers for console and webpage routing
- url: /redirect   
script: redirecter/redirecter.go
- url: /admin_console/choose   
script: admin_console/choose.go
- url: /post-request   
script: webpage/post-request.go
- url: /console   
script: console/console.go
#handlers for static files
- url: /css/console.css   
static_files: console/page/css/console.css   upload: console/page/css/console.css
- url: /console/page   
static_dir: console/page
- url: /   
static_files: webpage/index.html   
upload: webpage/index.html
- url: /   
static_dir: webpage
- url: /css   
static_dir: webpage/css
- url: /js   
static_dir: webpage/js
- url: /img   
static_dir: webpage/img
- url: /fonts   
static_dir: webpage/fonts

And my console.go file:

package console
import (
&quot;appengine&quot;
&quot;appengine/user&quot;
&quot;database/sql&quot;
_ &quot;github.com/go-sql-driver/mysql&quot;
&quot;html/template&quot;
&quot;io/ioutil&quot;
&quot;net/http&quot;
&quot;strconv&quot;
&quot;time&quot;
)
//for deployment
var dbConnectString string = &quot;****************************&quot;
//for local testing
//var dbConnectString string = &quot;root@/party&quot;
func init() {
http.HandleFunc(&quot;/console&quot;, consoleHandler)
}
func consoleHandler(w http.ResponseWriter, r *http.Request) {
redirectIfNeeded(w, r)
c := appengine.NewContext(r)
u := user.Current(c)
logoutUrl, e := user.LogoutURL(c, &quot;/redirect&quot;)
if e != nil {
panic(e)
}
email := u.Email
data := WebpageData{LogoutUrl: logoutUrl, UserName: email, NewPartyUrl: &quot;/console/newparty&quot;}
template := template.Must(template.New(&quot;template&quot;).Parse(generateUnsignedHtml(u)))
err := template.Execute(w, data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func generateUnsignedHtml(u *user.User) string {
firstPart := fileValue(&quot;./console/page/firstPart.html&quot;)
table := generateTable(u)
secondPart := fileValue(&quot;./console/page/secondPart.html&quot;)
html := firstPart + table + secondPart
return html
}
func generateTable(u *user.User) string {
con, e := sql.Open(&quot;mysql&quot;, dbConnectString)
if e != nil {
panic(e)
}
defer con.Close()
var parties []Party
partyRows, err := con.Query(&quot;select id, name, datetime, host, location from parties where author=&#39;&quot; + u.Email + &quot;&#39;;&quot;)
if err != nil {
panic(err)
}
var id int
var name string
var datetime string
var host string
var location string
for partyRows.Next() {
partyRows.Scan(&amp;id, &amp;name, &amp;datetime, &amp;host, &amp;location)
parties = append(parties, Party{Id: id, Name: name, DatetimeString: datetime, Host: host, Location: location})
}
html := &quot;&quot;
for i, party := range parties {
actionsHtml := &quot;&lt;a href=\&quot;/console/edit?id=&quot; + strconv.Itoa(party.Id) + &quot;\&quot; class=\&quot;uk-button uk-button-primary editButton\&quot;&gt;Edit&lt;/a&gt; &lt;a href=\&quot;/console/delete?id=&quot; + strconv.Itoa(party.Id) + &quot;\&quot; class=\&quot;uk-button uk-button-danger\&quot;&gt;Delete&lt;/a&gt;&quot;
html += &quot;&lt;tr&gt;&quot; + makeTd(strconv.Itoa(i+1)) + makeTd(party.Name) + makeTd(party.DatetimeString) + makeTd(party.Host) + makeTd(party.Location) + makeTd(actionsHtml) + &quot;&lt;/tr&gt;&quot;
}
html += &quot;&lt;/table&gt;&quot;
return html
}
func makeTd(content string) string {
return &quot;&lt;td&gt;&quot; + content + &quot;&lt;/td&gt;&quot;
}
func redirectIfNeeded(w http.ResponseWriter, r *http.Request) {
expire := time.Date(2000, 1, 1, 1, 1, 1, 0, time.UTC)
cookie := &amp;http.Cookie{Name: &quot;ACSID&quot;, Value: &quot;&quot;, Expires: expire, HttpOnly: true}
http.SetCookie(w, cookie)
cookie2 := &amp;http.Cookie{Name: &quot;SACSID&quot;, Value: &quot;&quot;, Expires: expire, HttpOnly: true}
http.SetCookie(w, cookie2)
c := appengine.NewContext(r)
u := user.Current(c)
if u == nil {
url, err := user.LoginURL(c, r.URL.String())
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set(&quot;Location&quot;, url)
w.WriteHeader(http.StatusFound)
return
}
con, e := sql.Open(&quot;mysql&quot;, dbConnectString)
if e != nil {
panic(e)
}
defer con.Close()
//check whether user is admin
admRows, error := con.Query(&quot;select email from admin_users;&quot;)
if error != nil {
panic(error)
}
var email string
isAdmin := false
for admRows.Next() {
admRows.Scan(&amp;email)
if email == u.Email {
isAdmin = true
}
}
//check if he is validated user
validRows, error2 := con.Query(&quot;select email from party_validated_users;&quot;)
if error2 != nil {
panic(error2)
}
email = &quot;&quot;
isValidated := false
for validRows.Next() {
validRows.Scan(&amp;email)
if email == u.Email {
isValidated = true
}
}
var url string
if user.IsAdmin(c) || isAdmin {
//user is declared as admin in db or is admin of gae app
//we are allready here
url = &quot;/console&quot;
} else if isValidated {
//user is validated
//we are allready here
url = &quot;/console&quot;
} else {
//user is not validated yet
url = &quot;/redirect&quot;
w.Header().Set(&quot;Location&quot;, url)
w.WriteHeader(http.StatusFound)
}
}
func fileValue(path string) string {
content, err := ioutil.ReadFile(path)
if err != nil {
panic(err)
}
return string(content)
}
type WebpageData struct {
LogoutUrl   string
UserName    string
NewPartyUrl string
}
type Party struct {
Id             int
Name           string
DatetimeString string
Host           string
Location       string
}

Any idea why this happens? Thanks in advance Go GAE应用在本地运行正常,但部署后出现404/无内容的错误。

答案1

得分: 2

对于Go应用程序,请将脚本处理程序设置为"_go_app"。例如:

handlers:
url: /api/.* 
script: _go_app

AppEngine将所有针对Go应用程序的请求分派给一个单独的编译可执行文件。这与Python不同,Python可以为每个处理程序指定不同的脚本。

英文:

For Go applications, set the script handler to "_go_app". For example:

handlers:
url: /api/.* 
script: _go_app

AppEngine dispatches all requests for Go applications to a single compiled executable. This is different from Python where you can specify a different script for each handler.

huangapple
  • 本文由 发表于 2015年3月26日 01:50:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/29262947.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定