CentOS6.4+nginx+go(FastCGI)+FileUpload

nginxのインストール

特に何もしていない

cat <<'EOF' > /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/6/$basearch/
gpgcheck=0
enabled=1
EOF

yum install nginx

Goのinstall

# Ver1.2 x64
wget https://go.googlecode.com/files/go1.2.linux-amd64.tar.gz

# extract to /usr/local/go
tar -C /usr/local -xzf go1.2.linux-amd64.tar.gz

# add the path of go to PATH env var
export PATH=$PATH:/usr/local/go/bin

nginxのGoファイルの設定

default.confで以下を追加

location ~ \.go$ {
    fastcgi_pass   127.0.0.1:13524;
    include        fastcgi.conf;
    client_max_body_size 100M;
}

Goのアプリは13524にListenし、ファイルの最大サイズは100MBとした。

GoAPPを作る

中身はpostでファイルを受け取って保存する。
基本的には↓のサイトを参考に作成。

http://sanatgersappa.blogspot.jp/2013/03/handling-multiple-file-uploads-in-go.html

FastCGIで動かすところは、以下を参考に作成

http://mwholt.blogspot.jp/2013/05/writing-go-golang-web-app-with-nginx.html

以下ソース

package main

import (
 "net"
 "net/http"
 "net/http/fcgi"
 "io"
 "os"
)

type FastCGIServer struct{}

func (s FastCGIServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {

	switch req.Method {
	case "GET":
		resp.Write([]byte("<h1>Get method</h1>"))
 
	case "POST":
		reader, err := req.MultipartReader()
 
		if err != nil {
			http.Error(resp, err.Error(), http.StatusInternalServerError)
			return
		}
 
		//copy each part to destination.
		for {
			part, err := reader.NextPart()
			if err == io.EOF {
				break
			}
 
			//if part.FileName() is empty, skip this iteration.
			if part.FileName() == "" {
				continue
			}
			dst, err := os.Create("/usr/share/nginx/html/files/" + part.FileName())
			defer dst.Close()
 
			if err != nil {
				http.Error(resp, err.Error(), http.StatusInternalServerError)
				return
			}
			
			if _, err := io.Copy(dst, part); err != nil {
				http.Error(resp, err.Error(), http.StatusInternalServerError)
				return
			}
		}
		resp.Write([]byte("<h1>Uploaded</h1>"))
	default:
		resp.WriteHeader(http.StatusMethodNotAllowed)
	}

}


func main() {
 listener, _ := net.Listen("tcp", "127.0.0.1:13524")
 srv := new(FastCGIServer)
 fcgi.Serve(listener, srv)
}

GETでは基本的に何もしていない。
出力先のディレクトリ、この場合は「/usr/share/nginx/html/files/」は予め作成しておく。

GoAPPの起動

runコマンドでBuildして起動。

go run uploader.go

buildコマンドでnativeな実行ファイルを作ってから実行

go build uploader.go

ファイルをアップするテストフォーム

先ほどのサイトの例を参考に作る。
actionには、GoAPPのURLを指定。

<!DOCTYPE html>
<html>
  <head>
    <title>File Upload Test</title>
  </head>
  <body>
    <div>
      <h1>File Upload Test</h1>
      <form class="form-signin" method="post" action="/uploader.go" enctype="multipart/form-data">
          <fieldset>
            <input type="file" name="myfiles" id="myfiles" multiple="multiple">
            <input type="submit" name="submit" value="Submit">
        </fieldset>
      </form>
    </div>
  </body>
</html>

cURLでファイルを送ってみる

"targetfile.txt"を送ってみる場合。

curl -F 'file=@targetfile.txt' http://localhost/uploader.go