最近我发现Revel是一个非常好的MVC Web框架,我想尝试一下。 问题是,我是Go的新手,一切看起来都有点不同。
使用PHP时,我只是将文件放入/var/www/
文件夹,或使用某些IDE,然后我可以打开浏览器并进行实时测试。使用RoR或Node.js会更容易,我只是转到本地项目文件夹(并不重要),在终端中运行一个命令,并且已经可以在localhost:3000
上看到结果。 / p>
这样,我在本地机器上有以下结构:
home
└── mark
└── code
├── php
│ └── my_php_app
└── ruby
└── my_ruby_app
他们都通过git同步。然后,当我想在我的远程机器上部署时,我只需将它们拉入/var/www/
并设置Apache2 / Nginx
但是如何使用Go应用程序执行此操作?我在家里的Linux机器和我的VPS上安装了Go。当我打开~/code/go/mygoapp
并尝试使用revel run
运行时,它表示在GOPATH
中找不到它。所以,我认为,我需要将所有Go项目与GOPATH
中的其他项目分开,可以是/usr/local/go/src/
或~/gocode/src/
。
如果我想将go
文件夹中的所有Go / Revel项目与php
和ruby
一起放在本地计算机上,我应该怎么做:
home
└── mark
└── code
├── go
│ └── my_revel_app
├── php
│ └── my_php_app
└── ruby
└── my_ruby_app
我如何以正确的方式在远程服务器上实际部署它们?
如果我仍然需要使用GOPATH,我如何命名包?是GOPATH/src/mygoapp
,GOPATH/src/mark/mygoapp
还是GOPATH/src/bitbucket.org/mark/mygoapp
(这个回购是私有的)?
我知道,这可能是一个菜鸟问题,但我在这里看不到逻辑。即使使用简单的Go程序,我也不需要将它们放到GOPATH中来运行。
答案 0 :(得分:1)
将目录(工作空间)添加到包含go source的GOPATH
,并符合结构src, pkg, bin
。您可以在GOPATH
中拥有任意数量的工作空间。在您的系统上相应地定义变量。您服务器上的GOPATH
很可能与您本地计算机上的git
不同。
您可以使用GOPATH
分享您的项目。在github或bitbucket上创建一个帐户,并进行同步。
您的go get
指向工作区。第一个用于存储notifyIntent
包。
答案 1 :(得分:1)
我觉得有一些误解。让我们继续努力。
PHP和Go之间存在一些根本区别,其中一个原因是PHP是一种解释性语言,而Go则是一种编译语言。
PHP的设计对于大多数应用程序来说都是一种所谓的解释语言,这意味着每次调用PHP文件时源代码都会被转换为机器可读的指令。
另一方面,Go是一种编译语言,这意味着源代码被编译为可执行二进制文件一次,并且静态链接是默认的,导致生成的可执行文件没有依赖关系(除了操作系统)它被编译为),甚至不是Go运行时。因此,您可以构建一个自给自足的Web应用程序,包括Web服务器和(使用特殊用途的Go包)甚至资源文件,如图像和样式表。
虽然您可以使用go run filename.go
,但它只是go build
的快捷方式并执行生成的已编译二进制文件,因为go run --help
的输出证明:
go run [build flags] [-exec xprog] gofiles ... [arguments ...]
运行编译并运行包含命名Go源文件的主包。 Go源文件被定义为以文字“.go”后缀结尾的文件。
默认情况下,'go run'直接运行已编译的二进制文件:'a.out arguments ...'。
我将向您展示$ GOPATH及其子目录是如何互连的。
让我们采用最简单的Web服务器示例:
package main
import (
"net/http"
"fmt"
)
// Default Request Handler
func defaultHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "<h1>Hello %s!</h1>", r.URL.Path[1:])
}
func main() {
http.HandleFunc("/", defaultHandler)
http.ListenAndServe(":8080", nil)
}
我把它放到这样的目录结构中,包括权限和文件大小。这是在OS X系统上
$GOPATH/src/github.com/mwmahlberg/DemoServer/
└── [-rw-r--r-- 178] server_main.go
现在,在DemoServer目录中调用GOOS=linux go build ./...
时,在我的情况下,交叉编译二进制文件以在linux上运行。二进制文件构建,目录如下所示:
$GOPATH/src/github.com/mwmahlberg/DemoServer/
├── [-rwxr-xr-x 6.2M] DemoServer
└── [-rw-r--r-- 178] server_main.go
请注意可执行文件server
,其大小为6.3M。但是,让我们检查一下:
$ file DemoServer
server: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
您实际上可以将此可执行文件复制到任何64位Linux并通过调用
运行它$ ./DemoServer
现在,使用http://hostname:8080/Mark调用相应的服务器,您将看到一个问候您的网站。
这并不是说这使得部署非常简单。您无需处理任何依赖关系,无需配置其他Web服务器。您可以直接复制二进制文件并运行它。但是,这并不妨碍您使用更复杂的方法,例如创建像.deb
或.rpm
或(我更喜欢)Docker镜像等软件包。
根据$GOPATH/src
下面的子目录:实际上,你完全可以自由地在那里整理你的包。但是,三胞胎
codehoster /用户名/包
是有原因的。 go get
命令实际上可以使用git,Mercurial和bzr站点自动下载包。有关详细信息,请参阅Package Publishing。是的,直接联系这些代码托管网站。 go get
实际上至少依赖于git。三元组仅反映代码的全局可达位置。当然,您可以将代码存储在$GOPATH/src/foobar
中并将其推送到github.com/mark/foobar
,尽管这变得相当不明显,特别是当我像在github.com上托管开放项目以及在bitbucket.org上托管所有其他项目时那样。
现在,让我们做一些有用的事情,并在调用日期网址时显示日期:
package main
import (
"net/http"
"fmt"
"time"
)
// Default Request Handler
func defaultHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "<h1>Hello %s!</h1>", r.URL.Path[1:])
}
func dateHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w,"<h1>%s</h1>",time.Now())
}
func main() {
http.HandleFunc("/date",dateHandler)
http.HandleFunc("/", defaultHandler)
http.ListenAndServe(":8080", nil)
}
但是,我们的main函数中仍然包含所有处理程序。我们将提取defaultHandler和dateHandler:
$GOPATH/src/github.com/mwmahlberg/DemoServer/
├── [-rw-r--r-- 214] dateHandler.go
├── [-rw-r--r-- 165] defaultHandler.go
└── [-rw-r--r-- 178] server_main.go
我们的server_main.go
现在看起来像这样:
package main
import (
"net/http"
)
func main() {
http.HandleFunc("/date",dateHandler)
http.HandleFunc("/", defaultHandler)
http.ListenAndServe(":8080", nil)
}
defaultHandler.go
:
package main
import (
"net/http"
"fmt"
)
func defaultHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "<h1>Hello %s!</h1>", r.URL.Path[1:])
}
我们的dateHandler.go
:
package main
import (
"net/http"
"fmt"
"time"
)
func dateHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w,"<h1>%s</h1>",time.Now())
}
让我们假设我们有一个特定于应用程序的可重用函数,我们希望将它们放入一个包中。为了这个例子,我们将为dateHandler提供一个Formatter。
$GOPATH/src/github.com/mwmahlberg/DemoServer/
├── [-rw-r--r-- 214] dateHandler.go
├── [-rw-r--r-- 165] defaultHandler.go
├── [drwxr-xr-x 102] formatter
│ └── [-rw-r--r-- 110] dateformatter.go
└── [-rw-r--r-- 178] server_main.go
dateformatter.go
的内容非常简单:
package formatter
import (
"time"
)
func FormatDate(d time.Time) string {
return d.Format(time.RFC850)
}
我们在日期处理程序中使用它:
package main
import (
"fmt"
"net/http"
"time"
"github.com/mwmahlberg/DemoServer/formatter"
)
func dateHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, formatter.FormatDate(time.Now()))
}
所以,我希望这会有所帮助。
答案 2 :(得分:0)
我会逐一回答你的问题:
1)如果我想将所有Go / Revel项目保存在go文件夹中,并将php和ruby保存在本地计算机上,我应该怎么做:
实际上你不能。 Go提出了一种构建Go代码结构的方法,理想情况是它应该如何遵循。 Go项目共享一个工作区,而不像其他项目那样,每个项目都有单独的工作区。
2)我如何以正确的方式在远程服务器上实际部署它们?
我能想到的一个有效方法是拥有一个单独的构建服务器,其中构建所有软件包以及获取远程软件包(github.com)。 Tar建造的项目。转到您的远程服务器,只需从bin运行可执行文件。这样可以节省生产服务器获取和构建远程包的时间。
3)如果我还需要使用GOPATH,我如何命名包?是GOPATH / src / mygoapp,GOPATH / src / mark / mygoapp还是GOPATH / src / bitbucket.org / mark / mygoapp(这个回购是私有的)?
我认为第三种方法是命名包的最合适方式,因为导入应该以主机名开头,然后是剩下的东西。