Go Webアプリケーションの作成

Goを使用してWebアプリケーションを作成することを考えたとき、自分で何か新しいことを試してみたいという欲求を追求しただけでした。 後で、プロジェクトで使用したクロスプラットフォームのGUIライブラリとしてWebシェルを使用できることに気付きました[ 1 ]。





エントリー


このレッスンと他のレッスンの違いは、標準のGoパッケージのみを検討することです。 私の仕事ではこれで十分であり、フレームワークを理解する意欲はありませんでした(たとえば、Revel [ 2 ])。 そこで、クエリのトピックに触れます。 たとえば、現時点では、インターネット上のサーバーにファイルをダウンロードする明確な例はありません。 そのため、今後の開発のためにスケルトンを作成できる記事を書くことにしました。



プログラムでは、コードの量が減少するため、エラーを処理しません。 したがって、明らかな関数引数のような些細なことは説明しません(詳細については、公式ドキュメント[ 3 ] [ 4 ]を参照してください)。 明確にするために、いくつかの点は厳密に形式的な言語ではないか、まったく真実ではない場合があります。



開始する


簡単なHello Worldプログラムから始めましょう。 これを行うには、関数ハンドラーを記述する必要があります。

func index(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-type", "text/plain") w.Write([]byte("Hello World!!!")) }
      
      





関数の引数はResponseWriterRequestです。 ResponseWriterは、HTTP応答を生成するために使用されるインターフェイスです; Request-サーバーが受信した、またはクライアントに送信することを意図したHTTP要求です。 この関数では、ヘッダーでコンテンツタイプを「プレーンテキスト」に設定し、クライアントに行を送信します。



次に、このハンドラーをパターンに「バインド」する必要があります。

 func main() { http.HandleFunc("/", index) http.ListenAndServe(":80", nil) }
      
      







HandleFuncを使用して、ハンドラー関数をパターンにバインドし、c、 ListenAndServeを使用して既にサーバーを直接起動します。 パターンは、「/」、「/ page0」、「/ page0 / page01」のいずれかです。 ただし、パターンの後はすべて適用されます。 たとえば、「/」と「/ page0」という2つのパターンが登録されています。 アドレスバーに「/ページ」を書き込むと、参照は「/」になり、「/ページ0 /ページ」にすると、「/ページ0」になります。 完全なコードは次のようになります。

 package main import ( "net/http" ) func index(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-type", "text/plain") w.Write([]byte("Hello World!!!")) } func main() { http.HandleFunc("/", index) http.ListenAndServe(":80", nil) }
      
      







ブラウザでコンパイル、実行(またはすぐに開始)し、サーバーが実行されているアドレス(ローカルマシンではlocalhost-127.0.0.1)に移動し、行を確認します。



テンプレートを使用します


プログラムの「埋め込み」htmlコードは、非常にく、編集には非常に不便です(特に大規模なプロジェクト)。

 fmt.Fprint(w, "<form target=\"_blank\" action=\"/exec/\" enctype=\"multipart/form-data\" method=\"post\">"+ "<input type=\"file\" name=\"imgfile\" />"+ "<input type=\"submit\" name=\"button\" value=\"Execute\" />"+ "</form>")
      
      







したがって、 テンプレートパッケージを使用して、読みやすさと編集のしやすさを向上させます。 最初に、ページの「バックボーン」を作成します(HTML5標準に焦点を当てます)。

 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>{{.Title}}</title> </head> <body> <p>{{.Msg}}</p> </body> </html>
      
      







タイトルメッセージは後でテキストに変わりますが、それについては後で詳しく説明します。 最初にデータ構造を記述する必要があり、それを関数に渡します。

 type page struct { Title string //     ,    ! Msg string //     ! }
      
      







次に、関数ハンドラーを作成します。

 func index(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-type", "text/html") t, _ := template.ParseFiles(“index.html”) t.Execute(w, &page{Title: "Just page", Msg: "Hello World"}) }
      
      







ParseFiles-指定されたファイルをダウンロードし、 Executeがテンプレートを処理し、データを置き換えて、それをwに書き込みます。



イベント処理


最後に残っているのは、ボタンを使用してページを作成したり、ファイルをアップロードしたりすることです。 この例では、サーバーは画像ファイルを受け入れ、品質0のJPEGに変換し(これにより、すべてが機能することが明確になります)、それを返します。



POSTメソッドを持つフォームを追加して、htmlテンプレートを変更します。

 <form target="_blank" action="/exec/" enctype="multipart/form-data" method="post"> <input type="file" name="imgfile" /> <input type="submit" name="button" value="Execute" /> </form>
      
      







関数ハンドラーを作成します。

 func index(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-type", "text/html") title := r.URL.Path[len("/"):] if title != "exec/" { t, _ := template.ParseFiles("index.html") t.Execute(w, &page{Title: "Convert Image"}) } else { imgfile, fhead, _ := r.FormFile("imgfile") img, ext, _ := image.Decode(imgfile) w.Header().Set("Content-type", "image/jpeg") w.Header().Set("Content-Disposition", "filename=\"" + fhead.Filename + "." + ext + "\"") jpeg.Encode(w, img, &jpeg.Options{0}) } }
      
      







タイトル変数は、パターンの後になります。 たとえば、アドレスが「http:// localhost / qwe /」の場合、 タイトルは「qwe /」になります。 さらに見てみると、「exec /」を使用していない場合は通常のページをロード、処理、表示し、「exec /」を使用している場合は入力ファイルを処理します。 FormFile-指定されたキー(そのようなフォームが複数ある場合は最初のフォーム)とファイルに関する情報を含むファイルを返します。 コンテンツタイプ(「image / jpeg」として)、ファイル名(サーバーはこの名前でブラウザーに応答を送信します)を設定し、画像を記録します。



完全なサンプルテキスト
index.html
 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>{{.Title}}</title> </head> <body> <form target="_blank" action="/exec/" enctype="multipart/form-data" method="post"> <input type="file" name="imgfile" /> <input type="submit" name="button" value="Execute" /> </form> </body> </html>
      
      







lesson.go
 package main import ( "net/http" "html/template" "image" "image/jpeg" _"image/png" _"image/gif" ) type page struct { Title string Msg string } func index(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-type", "text/html") title := r.URL.Path[len("/"):] if title != "exec/" { t, _ := template.ParseFiles("index.html") t.Execute(w, &page{Title: "Convert Image"}) } else { imgfile, fhead, _ := r.FormFile("imgfile") img, ext, _ := image.Decode(imgfile) w.Header().Set("Content-type", "image/jpeg") w.Header().Set("Content-Disposition", "filename=\"" + fhead.Filename + "." + ext + "\"") jpeg.Encode(w, img, &jpeg.Options{0}) } } func main() { http.HandleFunc("/", index) http.ListenAndServe(":80", nil) }
      
      











そしてもう1つ、テンプレートでローカルファイル(イメージファイルなど)を使用する場合、ハンドラーを記述するか、 httpパッケージのFileServerを使用する必要があります。 最初のケースでは、次のようなものがあります。

 func logo(w http.ResponseWriter, r *http.Request) { file, _ := ioutil.ReadFile("img/logo.png") w.Write(file) } <...> http.HandleFunc("/img/logo.png", logo) <...>
      
      







第二に、すべてが簡単です。 すべてのファイルを記述する必要はありません:

 <...> http.Handle("/img/", http.StripPrefix("/img/", http.FileServer(http.Dir("./img/")))) <...>
      
      







おわりに


このように、GoでWebアプリケーションを作成できることがどれほど簡単でわかりやすいかを示しました。 Goの利点は、言語自体のシンプルさ、httpプロトコルを使用するためのパッケージのシンプルさ、テンプレートを使用できること、および純粋なGoで記述されたコードがアーキテクチャとオペレーティングシステムから独立していることです。 Goは現在、FreeBSD(x86、amd64、arm)、NetBSD(x86、amd64)、GNU / Linux(x86、amd64、arm)、MacOS X(x86、amd64)、Windows(x86、amd64)をサポートしています。






[1] mapitemeditor.sourceforge.net

[2] habrahabr.ru/post/162115

[3] golang.org/doc

[4] golang.org/pkg



All Articles