英文:
Reading a local file in Google App Engine with Go
问题
我正在尝试在Google App Engine上使用Go而不是Python来构建我的网站。但是当我在本地测试我的脚本时,我一直遇到这个错误。
panic: runtime error: invalid memory address or nil pointer dereference
我很困惑,但是如果我注释掉以下代码,它将可以正常运行。
channel <- buffer[0:dat]
所以我可能在使用通道时出错了,有人可以帮忙吗?
编辑:
这是可工作的代码,非常感谢Kevin Ballard帮助我解决了这个问题。
package defp
import (
"fmt"
"http"
"os"
)
func getContent(filename string, channel chan []byte) {
file, err := os.OpenFile(filename, os.O_RDONLY, 0666)
defer file.Close()
if err == nil {
fmt.Printf("FILE FOUND : " + filename + " \n")
buffer := make([]byte, 16)
dat, err := file.Read(buffer)
for err == nil {
fmt.Printf("herp")
channel <- buffer[0:dat]
buffer = make([]byte, 16)
dat, err = file.Read(buffer)
}
close(channel)
fmt.Printf("DONE READING\n")
} else {
fmt.Printf("FILE NOT FOUND : " + filename + " \n")
}
}
func writeContent(w http.ResponseWriter, channel chan []byte) {
fmt.Printf("ATTEMPTING TO WRITE CONTENT\n")
go func() {
for bytes := range channel {
w.Write(bytes)
fmt.Printf("BYTES RECEIVED\n")
}
}()
fmt.Printf("FINISHED WRITING\n")
}
func load(w http.ResponseWriter, path string) {
fmt.Printf("ATTEMPTING LOAD " + path + "\n")
channel := make(chan []byte, 50)
writeContent(w, channel)
getContent(path, channel)
}
func handle(w http.ResponseWriter, r *http.Request) {
fmt.Printf("HANDLING REQUEST FOR " + r.URL.Path[1:] + "\n")
load(w, r.URL.Path[1:])
}
func init() {
http.HandleFunc("/", handle)
}
英文:
I'm trying to use go instead of python for my website on google app engine. But I keep getting this error with my script when I test locally.
panic: runtime error: invalid memory address or nil pointer dereference
I'm pretty confused, however it will run without error if I comment out
channel <- buffer[0:dat]
So I must be using channels incorrectly, Any help?
Edit:
This is the working code, many thanks to Kevin Ballard for helping me get this one.
package defp
import (
"fmt"
"http"
"os"
)
func getContent(filename string, channel chan []byte) {
file, err := os.OpenFile(filename, os.O_RDONLY, 0666)
defer file.Close()
if err == nil {
fmt.Printf("FILE FOUND : " + filename + " \n")
buffer := make([]byte, 16)
dat, err := file.Read(buffer)
for err == nil {
fmt.Printf("herp")
channel <- buffer[0:dat]
buffer = make([]byte, 16)
dat, err = file.Read(buffer)
}
close(channel)
fmt.Printf("DONE READING\n")
} else {
fmt.Printf("FILE NOT FOUND : " + filename + " \n")
}
}
func writeContent(w http.ResponseWriter, channel chan []byte) {
fmt.Printf("ATTEMPTING TO WRITE CONTENT\n")
go func() {
for bytes := range channel {
w.Write(bytes)
fmt.Printf("BYTES RECEIVED\n")
}
}()
fmt.Printf("FINISHED WRITING\n")
}
func load(w http.ResponseWriter, path string) {
fmt.Printf("ATTEMPTING LOAD " + path + "\n")
channel := make(chan []byte, 50)
writeContent(w, channel)
getContent(path, channel)
}
func handle(w http.ResponseWriter, r *http.Request) {
fmt.Printf("HANDLING REQUEST FOR " + r.URL.Path[1:] + "\n")
load(w, r.URL.Path[1:])
}
func init() {
http.HandleFunc("/", handle)
}
答案1
得分: 5
你的程序有时会发生恐慌的原因是,在程序退出load函数后,有时会写入w http.ResponseWriter。http包在程序退出处理程序函数时会自动关闭http.ResponseWriter。在writeContent函数中,程序有时会尝试向已关闭的http.ResponseWriter写入。
顺便说一下:如果使用io.Copy函数,可以使程序源代码更小。
为了始终获得可预测的行为,请确保您希望程序在HTTP请求响应中执行的所有工作都在退出处理程序函数之前完成。例如:
func writeContent(w http.ResponseWriter, channel chan []byte) {
fmt.Printf("尝试写入内容\n")
for bytes := range channel {
w.Write(bytes)
fmt.Printf("接收到字节\n")
}
fmt.Printf("写入完成\n")
}
func load(w http.ResponseWriter, path string) {
fmt.Printf("尝试加载 " + path + "\n")
channel := make(chan []byte)
workDone := make(chan byte)
go func() {
writeContent(w, channel)
workDone <- 1 //发送任意值
}()
go func() {
getContent(path, channel)
workDone <- 2 //发送任意值
}()
<-workDone
<-workDone
}
func handle(w http.ResponseWriter, r *http.Request) {
fmt.Printf("处理请求 " + r.URL.Path[1:] + "\n")
load(w, r.URL.Path[1:])
}
英文:
The reason why your program sometimes panics is that it is sometimes writing to <code>w http.ResponseWriter</code> after the program exits the <code>load</code> function. The <code>http</code> package automatically closes the <code>http.ResponseWriter</code> when the program exits the handler function. In function <code>writeContent</code>, the program will sometimes attempt to write to a closed <code>http.ResponseWriter</code>.
BTW: You can make the program source code much smaller if you use the <code>io.Copy</code> function.
To always get predictable behavior, make sure that all work that you want the program to perform in response to a HTTP request is done before you exit the handler function. For example:
func writeContent(w http.ResponseWriter, channel chan []byte) {
fmt.Printf("ATTEMPTING TO WRITE CONTENT\n")
for bytes := range channel {
w.Write(bytes)
fmt.Printf("BYTES RECEIVED\n")
}
fmt.Printf("FINISHED WRITING\n")
}
func load(w http.ResponseWriter, path string) {
fmt.Printf("ATTEMPTING LOAD " + path + "\n")
channel := make(chan []byte)
workDone := make(chan byte)
go func() {
writeContent(w, channel)
workDone <- 1 //Send an arbitrary value
}()
go func() {
getContent(path, channel)
workDone <- 2 //Send an arbitrary value
}()
<-workDone
<-workDone
}
func handle(w http.ResponseWriter, r *http.Request) {
fmt.Printf("HANDLING REQUEST FOR " + r.URL.Path[1:] + "\n")
load(w, r.URL.Path[1:])
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论