Example of a package of the server on Golang

x_focus · · 1376 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。
Example of a package of the server on Golang
Programming Go 1 year, 10 months ago
In language Go, as a matter of fact, there are two basic essences: executed files, and packages. In this article I suggest to consider the second on a small example.

The package is a library of functions and structures. According to the destination it reminds standard, all well-known, linkuemye libraries. The package in Go defines visibility area. If the name of variables or structures begins with a small letter, they local (area of visibility of a package), if with big, the exported. Local structures and functions can be used only in a package, global inside and out of a package. The let feature is easy be know on an example of work with a package json, a part of standard libraries of language.

The similar code will return an error.

type Link struct {
name  string
url string
title string
class string

links := make(map[string]Link)
if err = json.Unmarshal(response, &links;); err != nil {
    return err

The matter is that we use functions from a package json, transferring structure c fields of local visibility (in function Unmarshal To structure fields Link Simply there is no access).

The package code should settle down according to his name that is if the package is called ru/sezn/server, That files *.go Will be in a folder server which will be podpapkoj sezn and ru.

Let's consider a package of a simple Web server which is used in ours a web applications: http://sezn.ru/ and http://hashcode.ru/

In language Go there is an own library representing the http-server. As the majority of developers have more than one site, to use directly the built in http-server it will not turn out (in system there is only one 80 port). For start we will use the module fastCGI Web server Apache2. The file of adjustment virtual hotsa applications is more low resulted.

<VirtualHost *:80>
   ServerAdmin webmaster@hashcode.ru

   DocumentRoot /path/to/bin/
   ServerName sezn.ru

   ErrorLog /var/log/apache2/sezn_error.log
   LogLevel warn
   CustomLog /var/log/apache2/sezn_warning.log combined

   AddHandler fastcgi-script our_bin
   FastCgiExternalServer /path/to/bin/our_bin -host

   RewriteEngine On
   RewriteRule ^(.*)$ /our_bin [QSA,L]

The server package is realised in the form of simple structure with a set of methods for processing of inquiries of files, registration vjushek, checks "kapchi" and so on. At the heart of system of routeing we use library Gorilla (http://www.gorillatoolkit.org/). For support kapchi was the library https://github.com/dchest/captcha is taken.

The basic structure of the server:

type Server struct {
Router    *mux.Router
Transport string
Addres    string
MediaPath string
CachedFiles map[string]*CachedFile
fn404     func(w http.ResponseWriter, r *http.Request)

For faster work we use keshirvoanie all files in a folder with mediej.

type CachedFile struct {
FileName  string
FullPath  string
FilePath  string
FileExt   string
FileData  []byte

The server realises the following public interface.

AddNamedHandler(pattern string, handler func(http.ResponseWriter, *http.Request), name string)
AddHandler(pattern string, handler func(http.ResponseWriter, *http.Request))
Reverse(name string) *mux.Route
Run() error
SetRootMediaPath(path string)
Set404ErrorHandler(fn func(w http.ResponseWriter, r *http.Request))
ServeHTTP(w http.ResponseWriter, r *http.Request)

And tazhe the interface with area of visibility of a package.
renderFile(w http.ResponseWriter, filename string) error

During initialization, we only create the basic structures.

func InitServer(transport, addres string) *Server {
server := &Server;{Router: &mux.Router;{}, Transport: transport, Addres: addres}
        return server

Then, on a course of initialization of modules, the basic application adds the called/not called functions output agents causing a method AddNamedHandler Or AddHandler. 

Code of function of registration of the output agent.

func (server *Server) AddNamedHandler(pattern string, handler func(http.ResponseWriter, *http.Request), name string) {
server.Router.HandleFunc(pattern, handler).Name(name)

For server start it is necessary to cause method Run. In it we keshiruem files (to a question on caching http://meta.hashcode.ru/questions/1158/) also register media the output agent fastCGI the report.

func (server *Server) Run() error {
l, err := net.Listen(server.Transport, server.Addres)
if err != nil {
return err

fcgi.Serve(l, server.Router)
return nil

Before method Run will be caused, it is necessary to establish the output agent who will be caused if the required file is not found. 

func (server *Server) Set404ErrorHandler(fn func(w http.ResponseWriter, r *http.Request)) {
server.fn404 = fn
server.Router.NotFoundHandler = server

Here there is a thin moment, we register the output agent of an error 404, transferring to library Gorilla our server. The server realises the interface of processing HTTP of inquiries. For it the method responds ServeHTTP.

func (server *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := server.renderFile(w, r.URL.Path)
if err != nil {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
server.fn404(w, r)

We register output agents of all vjushek in system of routeing of library Gorilla. If the output agent is not found, we try to find a file, with such name. If the file is not present, we cause the output agent of an error 404.

Method of reading of media of files in memory:

func (server *Server) cacheFiles() {
server.CachedFiles = make(map[string]*CachedFile)
dir, _ := filepath.Abs(server.MediaPath)

  filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
file, err := ioutil.ReadFile(path)
filePath := strings.Replace(path, dir, "", -1)
server.CachedFiles[filePath] = &CachedFile; {
FileName: info.Name(),
FullPath: path,
FilePath: filePath,
FileExt: filepath.Ext(path),
FileData: file,
return nil

At the moment of inquiry of a file, it is necessary for us to look only at occurrence of a corresponding way to the dictionary with files and to generate the answer. If file with we request the address it is not found, we will try to find it on a disk.

func (server *Server) renderFile(w http.ResponseWriter, filename string) error {
var file []byte
var ext string
var err error 

if cachedFile, exist := server.CachedFiles[filename]; exist {
file = cachedFile.FileData
ext = cachedFile.FileExt
} else {
file, err = ioutil.ReadFile(server.MediaPath + filename)
if err != nil {
return err
ext = filepath.Ext(server.MediaPath + filename)

if ext != "" {
w.Header().Set("Content-Type", mime.TypeByExtension(ext))
if file != nil {

return nil

The name “server” is far not the unique. We place packages using notation Java. When we will want to export a package, the full name will look as ru/sezn/server. For creation of a package we use the program delivered with language. 

go get ru/sezn/server

Here basically and all. I will be glad to answer questions in comments to a post or in a corresponding branch on HeshKode (http://hashcode.ru/questions/tagged/go/).

P. S. The given package was altered last time under Go RC1 and can not work with later/early version of language.





查看原文:Example of a package of the server on Golang

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:1006366459

1376 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传