这是我的经纪人:
func VideosStoreHandler(w http.ResponseWriter, r *http.Request) {
r.ParseMultipartForm(32 << 20)
clientFile, header, err := r.FormFile("file")
if err != nil {
logs.Create(logs.LevelError, "[VideosStoreHandler] Unable to parse uploaded file: "+err.Error())
return
}
defer clientFile.Close()
tfn := fmt.Sprintf("%s%d%s", config.TmpDir, time.Now().UnixNano(), filepath.Ext(header.Filename))
tmpFile, err := os.OpenFile(tfn, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
logs.Create(logs.LevelError, "[VideosStoreHandler] Unable to create temporary file: "+err.Error())
return
}
defer tmpFile.Close()
io.Copy(tmpFile, clientFile)
msg := fmt.Sprintf("[VideosStoreHandler] Video %q uploaded with filename: %q.", r.FormValue("name"), header.Filename)
logs.Create(logs.LevelInfo, msg)
vid := videos.CreateVideo(r.FormValue("name"), filepath.Ext(header.Filename))
go util.ParseVideo(vid, r.FormValue("name"), tmpFile.Name())
http.Redirect(w, r, "/admin/logs", http.StatusTemporaryRedirect)
}
ParseVideo
功能:
func ParseVideo(vid int64, vname, fname string) {
defer os.Remove(fname)
file, err := os.Open(fname)
if err != nil {
logs.Create(logs.LevelError, "[ParseVideo] Unable to open temporary file: "+err.Error())
return
}
defer file.Close()
fstat, err := file.Stat()
if err != nil {
logs.Create(logs.LevelError, "[ParseVideo] Unable to get file info: "+err.Error())
return
}
fileSize := fstat.Size()
totalPartsNum := uint64(math.Ceil(float64(fileSize) / float64(config.ChunkSize)))
prefix := fmt.Sprintf("%d", time.Now().UnixNano())
time.Sleep(5 * time.Second) // NOTE: This is intentional, for testing.
for i := uint64(0); i < totalPartsNum; i++ {
time.Sleep(5 * time.Second) // NOTE: This is intentional, for testing.
partSize := int(math.Min(config.ChunkSize, float64(fileSize-int64(i*config.ChunkSize))))
partBuffer := make([]byte, partSize)
file.Read(partBuffer)
encrypted, err := crypt.EncryptChunk(partBuffer)
if err != nil {
logs.Create(logs.LevelError, "[ParseVideo] Failed to encrypt chunk file: "+err.Error())
return
}
fileName := fmt.Sprintf("%s%s%d", config.ChunksDir, prefix, i)
chunkFile, err := os.Create(fileName)
if err != nil {
logs.Create(logs.LevelError, "[ParseVideo] Unable to create chunk file: "+err.Error())
return
}
chunkFile.Close()
err = ioutil.WriteFile(fileName, encrypted, os.ModeAppend)
if err != nil {
logs.Create(logs.LevelError, "[ParseVideo] Writing to chunk file failed: "+err.Error())
return
}
videos.CreateChunk(vid, fileName)
msg := fmt.Sprintf("[ParseVideo] Chunk %d of %q stored in %q.",
i, vname, fileName)
logs.Create(logs.LevelInfo, msg)
}
msg := fmt.Sprintf("[ParseVideo] %q processing finished without errors.", vname)
logs.Create(logs.LevelSuccess, msg)
}
提供LogsHandler
的 /admin/logs
:
func LogsHandler(w http.ResponseWriter, r *http.Request) {
data := struct {
Items []logs.Log
}{}
rows, err := logs.FetchAll()
if err != nil {
logs.Create(logs.LevelError, "[LogsHandler] Failed to fetch logs: "+err.Error())
return
}
for rows.Next() {
var item logs.Log
if err := rows.Scan(&item.Level, &item.Message, &item.Timestamp); err != nil {
logs.Create(logs.LevelError, "[LogsHandler] Failed to scan log items: "+err.Error())
return
}
data.Items = append(data.Items, item)
}
if err := rows.Err(); err != nil {
logs.Create(logs.LevelError, "[LogsHandler] SQL Error: "+err.Error())
return
}
template.Render("admin/logs.html", data, w)
}
Render
功能:
func Render(filePath string, data interface{}, w http.ResponseWriter) {
fp := path.Join("templates", filePath)
tmpl, err := template.ParseFiles(fp, "templates/layouts/master.html")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if err := tmpl.Execute(w, data); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
我想在日志中显示解析进度。日志工作正常,但http.Redirect不起作用(我在其他处理程序中使用此方法,我需要重定向,它们工作正常),我的浏览器显示此错误:
通过Chrome开发人员工具检查响应,网络选项卡中没有响应。通过手动浏览到/admin/logs
,它加载就好了!
问题出在哪里?