我有一个网站,该网站由三个较小的“独立”子网站组成:
其中
doc
是使用Hugo :: A fast and modern static website engine创建的站点,editor
是mxgraph Graphditor example;其余文件构成一个手工制作的登录页面。除了部署到任何Web服务器之外,我还希望将站点作为“独立应用程序”进行分发。为此,我在go中编写了这个非常简单的服务器:
package main
import (
flag "github.com/ogier/pflag"
"fmt"
"net/http"
"net/http/httputil"
"os"
"path/filepath"
)
var port = flag.IntP("port", "p", 80, "port to serve at")
var dir = flag.StringP("dir", "d", "./", "dir to serve from")
var verb = flag.BoolP("verbose", "v", false, "")
func init() {
flag.Parse();
}
type justFilesFilesystem struct {
fs http.FileSystem;
}
type neuteredReaddirFile struct {
http.File
}
func (fs justFilesFilesystem) Open(name string) (http.File, error) {
f, err := fs.fs.Open(name)
if err != nil { return nil, err; }
return neuteredReaddirFile{f}, nil
}
func (f neuteredReaddirFile) Readdir(count int) ([]os.FileInfo, error) {
return nil, nil;
}
func loggingHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requestDump, err := httputil.DumpRequest(r, true)
if err != nil { fmt.Println(err); }
fmt.Println(string(requestDump))
h.ServeHTTP(w, r)
})
}
func main() {
str, err := filepath.Abs(*dir)
if err != nil { os.Exit(1); }
fmt.Printf("Serving at port %d from dir %s\n\n",*port,str)
http.ListenAndServe(fmt.Sprintf(":%d",*port), loggingHandler(http.FileServer(justFilesFilesystem{http.Dir(*dir)})))
}
结果,我可以运行
simpleserver -d <path-to-mysite>
并通过localhost
,localhost/doc
和localhost/editor
浏览站点。然后,我想使用自定义(子)域,例如
mylocal.app
,doc.mylocal.app
和editor.mylocal.app
。因此,我在/etc/hosts
文件中添加了以下行:127.0.0.1 mylocal.app
。因此,我可以浏览mylocal.app
,mylocal.app/editor
和mylocal.app/doc
。而且,我能够使用不同的软件包将其更改为mylocal.app
,mylocal.app:<editor-port>
和mylocal.app:<doc-port>
。但是,当我尝试使用子域时,无法正确解决该问题,因此任何反向代理策略都将不起作用。由于不支持通配符,因此我可以在
/etc/hosts
文件中添加其他条目,但我希望避免使用它。虽然,另一种解决方案是运行dnsmasq,但我想保持应用程序独立。我找到了一些等效的golang软件包。但是,我感觉支持了很多我并不需要的功能。
此外,由于我实际上不必解析任何IP,而是提供
localhost
的别名,所以我认为代理就足够了。这也将更易于配置,因为用户只能配置浏览器,并且不需要系统范围的修改。但是,来自用户的所有流量都会被我的应用“过滤”。这样对吗?如果是这样,您能指出我要以最干净的方式实现它的任何引用吗?我知道这是很主观的,但是我的意思是较短的代码段(例如10行代码),以便用户可以轻松查看正在发生的事情。
编辑
我想使用类似的东西:
func main() {
mymux := http.NewServeMux()
mymux.HandleFunc("*.mylocal.app", myHandler)
mymux.HandleFunc("*", <systemDefaultHandler>)
http.ListenAndServe(":8080", mymux)
}
或者
func main() {
mymux := http.NewServeMux()
mymux.HandleFunc("editor.mylocal.app", editorHandler)
mymux.HandleFunc("doc.mylocal.app", docHandler)
mymux.HandleFunc("*.mylocal.app", rootHandler)
mymux.HandleFunc("*", <systemDefaultHandler>)
http.ListenAndServe(":8080", mymux)
}
这些只是片段。一个完整的示例是this,它在@ Steve101的注释中被引用。
但是,现在,我不知道什么是systemDefaultHandler。那里还没有解决。
除此之外,@ faraz建议使用goproxy。我认为
HTTP/HTTPS transparent proxy
是我正在寻找的默认处理程序。但是,仅使用软件包来完成此操作对我来说似乎太过分。我可以使用内置资源实现相同的功能吗? 最佳答案
不幸的是,没有通过Go做到这一点的简单方法。您将需要像dnsmasq一样拦截系统的DNS请求,这不可避免地需要对系统DNS配置(Linux中的/etc/resolv.conf
,Mac上的/etc/resolver
或防火墙规则)进行一些修改,以将DNS请求路由到您的应用。使用DNS的缺点是,您需要在应用程序内部构建类似于pow.cx的DNS服务器,这似乎不必要地复杂。
由于不可避免地要进行系统配置,所以我投票赞成在启动时或在添加/删除目录时(通过fsnotify)对hosts文件进行更改。在关闭时,您也可以清除添加的条目。
如果您希望将这些更改隔离到特定的浏览器而不是进行系统范围的更改,则可以始终通过goproxy之类的代理服务器运行您的应用程序,并告诉您的浏览器使用该代理来处理请求。例如,您可以通过Chrome的首选项或设置--proxy-server
标志来执行此操作:
--proxy-server=<scheme>=<uri>[:<port>][;...] | <uri>[:<port>] | "direct://"
有关更多详细信息,请参见Chrome's network settings docs。
另外,如果您愿意使用浏览器的配置,则可以根据需要使用an extension来处理请求。