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

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

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

问题

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

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

  1. application: party-serverside
  2. version: alpha-1
  3. runtime: go
  4. api_version: go1
  5. handlers:
  6. #handlers for api
  7. - url: /api/.*
  8. script: api/api.go
  9. #handlers for console and webpage routing
  10. - url: /redirect
  11. script: redirecter/redirecter.go
  12. - url: /admin_console/choose
  13. script: admin_console/choose.go
  14. - url: /post-request
  15. script: webpage/post-request.go
  16. - url: /console
  17. script: console/console.go
  18. #handlers for static files
  19. - url: /css/console.css
  20. static_files: console/page/css/console.css
  21. upload: console/page/css/console.css
  22. - url: /console/page
  23. static_dir: console/page
  24. - url: /
  25. static_files: webpage/index.html
  26. upload: webpage/index.html
  27. - url: /
  28. static_dir: webpage
  29. - url: /css
  30. static_dir: webpage/css
  31. - url: /js
  32. static_dir: webpage/js
  33. - url: /img
  34. static_dir: webpage/img
  35. - url: /fonts
  36. static_dir: webpage/fonts

这是我的 console.go 文件:

  1. package console
  2. import (
  3. "appengine"
  4. "appengine/user"
  5. "database/sql"
  6. _ "github.com/go-sql-driver/mysql"
  7. "html/template"
  8. "io/ioutil"
  9. "net/http"
  10. "strconv"
  11. "time"
  12. )
  13. //for deployment
  14. var dbConnectString string = "****************************"
  15. //for local testing
  16. //var dbConnectString string = "root@/party"
  17. func init() {
  18. http.HandleFunc("/console", consoleHandler)
  19. }
  20. func consoleHandler(w http.ResponseWriter, r *http.Request) {
  21. redirectIfNeeded(w, r)
  22. c := appengine.NewContext(r)
  23. u := user.Current(c)
  24. logoutUrl, e := user.LogoutURL(c, "/redirect")
  25. if e != nil {
  26. panic(e)
  27. }
  28. email := u.Email
  29. data := WebpageData{LogoutUrl: logoutUrl, UserName: email, NewPartyUrl: "/console/newparty"}
  30. template := template.Must(template.New("template").Parse(generateUnsignedHtml(u)))
  31. err := template.Execute(w, data)
  32. if err != nil {
  33. http.Error(w, err.Error(), http.StatusInternalServerError)
  34. }
  35. }
  36. func generateUnsignedHtml(u *user.User) string {
  37. firstPart := fileValue("./console/page/firstPart.html")
  38. table := generateTable(u)
  39. secondPart := fileValue("./console/page/secondPart.html")
  40. html := firstPart + table + secondPart
  41. return html
  42. }
  43. func generateTable(u *user.User) string {
  44. con, e := sql.Open("mysql", dbConnectString)
  45. if e != nil {
  46. panic(e)
  47. }
  48. defer con.Close()
  49. var parties []Party
  50. partyRows, err := con.Query("select id, name, datetime, host, location from parties where author='" + u.Email + "';")
  51. if err != nil {
  52. panic(err)
  53. }
  54. var id int
  55. var name string
  56. var datetime string
  57. var host string
  58. var location string
  59. for partyRows.Next() {
  60. partyRows.Scan(&id, &name, &datetime, &host, &location)
  61. parties = append(parties, Party{Id: id, Name: name, DatetimeString: datetime, Host: host, Location: location})
  62. }
  63. html := ""
  64. for i, party := range parties {
  65. 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>"
  66. html += "<tr>" + makeTd(strconv.Itoa(i+1)) + makeTd(party.Name) + makeTd(party.DatetimeString) + makeTd(party.Host) + makeTd(party.Location) + makeTd(actionsHtml) + "</tr>"
  67. }
  68. html += "</table>"
  69. return html
  70. }
  71. func makeTd(content string) string {
  72. return "<td>" + content + "</td>"
  73. }
  74. func redirectIfNeeded(w http.ResponseWriter, r *http.Request) {
  75. expire := time.Date(2000, 1, 1, 1, 1, 1, 0, time.UTC)
  76. cookie := &http.Cookie{Name: "ACSID", Value: "", Expires: expire, HttpOnly: true}
  77. http.SetCookie(w, cookie)
  78. cookie2 := &http.Cookie{Name: "SACSID", Value: "", Expires: expire, HttpOnly: true}
  79. http.SetCookie(w, cookie2)
  80. c := appengine.NewContext(r)
  81. u := user.Current(c)
  82. if u == nil {
  83. url, err := user.LoginURL(c, r.URL.String())
  84. if err != nil {
  85. http.Error(w, err.Error(), http.StatusInternalServerError)
  86. return
  87. }
  88. w.Header().Set("Location", url)
  89. w.WriteHeader(http.StatusFound)
  90. return
  91. }
  92. con, e := sql.Open("mysql", dbConnectString)
  93. if e != nil {
  94. panic(e)
  95. }
  96. defer con.Close()
  97. //check whether user is admin
  98. admRows, error := con.Query("select email from admin_users;")
  99. if error != nil {
  100. panic(error)
  101. }
  102. var email string
  103. isAdmin := false
  104. for admRows.Next() {
  105. admRows.Scan(&email)
  106. if email == u.Email {
  107. isAdmin = true
  108. }
  109. }
  110. //check if he is validated user
  111. validRows, error2 := con.Query("select email from party_validated_users;")
  112. if error2 != nil {
  113. panic(error2)
  114. }
  115. email = ""
  116. isValidated := false
  117. for validRows.Next() {
  118. validRows.Scan(&email)
  119. if email == u.Email {
  120. isValidated = true
  121. }
  122. }
  123. var url string
  124. if user.IsAdmin(c) || isAdmin {
  125. //user is declared as admin in db or is admin of gae app
  126. //we are allready here
  127. url = "/console"
  128. } else if isValidated {
  129. //user is validated
  130. //we are allready here
  131. url = "/console"
  132. } else {
  133. //user is not validated yet
  134. url = "/redirect"
  135. w.Header().Set("Location", url)
  136. w.WriteHeader(http.StatusFound)
  137. }
  138. }
  139. func fileValue(path string) string {
  140. content, err := ioutil.ReadFile(path)
  141. if err != nil {
  142. panic(err)
  143. }
  144. return string(content)
  145. }
  146. type WebpageData struct {
  147. LogoutUrl string
  148. UserName string
  149. NewPartyUrl string
  150. }
  151. type Party struct {
  152. Id int
  153. Name string
  154. DatetimeString string
  155. Host string
  156. Location string
  157. }

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

英文:

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):

  1. application: party-serverside version: alpha-1 runtime: go
  2. api_version: go1
  3. handlers:
  4. #handlers for api
  5. - url: /api/.*
  6. script: api/api.go
  7. #handlers for console and webpage routing
  8. - url: /redirect
  9. script: redirecter/redirecter.go
  10. - url: /admin_console/choose
  11. script: admin_console/choose.go
  12. - url: /post-request
  13. script: webpage/post-request.go
  14. - url: /console
  15. script: console/console.go
  16. #handlers for static files
  17. - url: /css/console.css
  18. static_files: console/page/css/console.css upload: console/page/css/console.css
  19. - url: /console/page
  20. static_dir: console/page
  21. - url: /
  22. static_files: webpage/index.html
  23. upload: webpage/index.html
  24. - url: /
  25. static_dir: webpage
  26. - url: /css
  27. static_dir: webpage/css
  28. - url: /js
  29. static_dir: webpage/js
  30. - url: /img
  31. static_dir: webpage/img
  32. - url: /fonts
  33. static_dir: webpage/fonts

And my console.go file:

  1. package console
  2. import (
  3. &quot;appengine&quot;
  4. &quot;appengine/user&quot;
  5. &quot;database/sql&quot;
  6. _ &quot;github.com/go-sql-driver/mysql&quot;
  7. &quot;html/template&quot;
  8. &quot;io/ioutil&quot;
  9. &quot;net/http&quot;
  10. &quot;strconv&quot;
  11. &quot;time&quot;
  12. )
  13. //for deployment
  14. var dbConnectString string = &quot;****************************&quot;
  15. //for local testing
  16. //var dbConnectString string = &quot;root@/party&quot;
  17. func init() {
  18. http.HandleFunc(&quot;/console&quot;, consoleHandler)
  19. }
  20. func consoleHandler(w http.ResponseWriter, r *http.Request) {
  21. redirectIfNeeded(w, r)
  22. c := appengine.NewContext(r)
  23. u := user.Current(c)
  24. logoutUrl, e := user.LogoutURL(c, &quot;/redirect&quot;)
  25. if e != nil {
  26. panic(e)
  27. }
  28. email := u.Email
  29. data := WebpageData{LogoutUrl: logoutUrl, UserName: email, NewPartyUrl: &quot;/console/newparty&quot;}
  30. template := template.Must(template.New(&quot;template&quot;).Parse(generateUnsignedHtml(u)))
  31. err := template.Execute(w, data)
  32. if err != nil {
  33. http.Error(w, err.Error(), http.StatusInternalServerError)
  34. }
  35. }
  36. func generateUnsignedHtml(u *user.User) string {
  37. firstPart := fileValue(&quot;./console/page/firstPart.html&quot;)
  38. table := generateTable(u)
  39. secondPart := fileValue(&quot;./console/page/secondPart.html&quot;)
  40. html := firstPart + table + secondPart
  41. return html
  42. }
  43. func generateTable(u *user.User) string {
  44. con, e := sql.Open(&quot;mysql&quot;, dbConnectString)
  45. if e != nil {
  46. panic(e)
  47. }
  48. defer con.Close()
  49. var parties []Party
  50. partyRows, err := con.Query(&quot;select id, name, datetime, host, location from parties where author=&#39;&quot; + u.Email + &quot;&#39;;&quot;)
  51. if err != nil {
  52. panic(err)
  53. }
  54. var id int
  55. var name string
  56. var datetime string
  57. var host string
  58. var location string
  59. for partyRows.Next() {
  60. partyRows.Scan(&amp;id, &amp;name, &amp;datetime, &amp;host, &amp;location)
  61. parties = append(parties, Party{Id: id, Name: name, DatetimeString: datetime, Host: host, Location: location})
  62. }
  63. html := &quot;&quot;
  64. for i, party := range parties {
  65. 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;
  66. 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;
  67. }
  68. html += &quot;&lt;/table&gt;&quot;
  69. return html
  70. }
  71. func makeTd(content string) string {
  72. return &quot;&lt;td&gt;&quot; + content + &quot;&lt;/td&gt;&quot;
  73. }
  74. func redirectIfNeeded(w http.ResponseWriter, r *http.Request) {
  75. expire := time.Date(2000, 1, 1, 1, 1, 1, 0, time.UTC)
  76. cookie := &amp;http.Cookie{Name: &quot;ACSID&quot;, Value: &quot;&quot;, Expires: expire, HttpOnly: true}
  77. http.SetCookie(w, cookie)
  78. cookie2 := &amp;http.Cookie{Name: &quot;SACSID&quot;, Value: &quot;&quot;, Expires: expire, HttpOnly: true}
  79. http.SetCookie(w, cookie2)
  80. c := appengine.NewContext(r)
  81. u := user.Current(c)
  82. if u == nil {
  83. url, err := user.LoginURL(c, r.URL.String())
  84. if err != nil {
  85. http.Error(w, err.Error(), http.StatusInternalServerError)
  86. return
  87. }
  88. w.Header().Set(&quot;Location&quot;, url)
  89. w.WriteHeader(http.StatusFound)
  90. return
  91. }
  92. con, e := sql.Open(&quot;mysql&quot;, dbConnectString)
  93. if e != nil {
  94. panic(e)
  95. }
  96. defer con.Close()
  97. //check whether user is admin
  98. admRows, error := con.Query(&quot;select email from admin_users;&quot;)
  99. if error != nil {
  100. panic(error)
  101. }
  102. var email string
  103. isAdmin := false
  104. for admRows.Next() {
  105. admRows.Scan(&amp;email)
  106. if email == u.Email {
  107. isAdmin = true
  108. }
  109. }
  110. //check if he is validated user
  111. validRows, error2 := con.Query(&quot;select email from party_validated_users;&quot;)
  112. if error2 != nil {
  113. panic(error2)
  114. }
  115. email = &quot;&quot;
  116. isValidated := false
  117. for validRows.Next() {
  118. validRows.Scan(&amp;email)
  119. if email == u.Email {
  120. isValidated = true
  121. }
  122. }
  123. var url string
  124. if user.IsAdmin(c) || isAdmin {
  125. //user is declared as admin in db or is admin of gae app
  126. //we are allready here
  127. url = &quot;/console&quot;
  128. } else if isValidated {
  129. //user is validated
  130. //we are allready here
  131. url = &quot;/console&quot;
  132. } else {
  133. //user is not validated yet
  134. url = &quot;/redirect&quot;
  135. w.Header().Set(&quot;Location&quot;, url)
  136. w.WriteHeader(http.StatusFound)
  137. }
  138. }
  139. func fileValue(path string) string {
  140. content, err := ioutil.ReadFile(path)
  141. if err != nil {
  142. panic(err)
  143. }
  144. return string(content)
  145. }
  146. type WebpageData struct {
  147. LogoutUrl string
  148. UserName string
  149. NewPartyUrl string
  150. }
  151. type Party struct {
  152. Id int
  153. Name string
  154. DatetimeString string
  155. Host string
  156. Location string
  157. }

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

答案1

得分: 2

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

  1. handlers:
  2. url: /api/.*
  3. script: _go_app

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

英文:

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

  1. handlers:
  2. url: /api/.*
  3. 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:

确定