我有一个网站,由三个较小的“独立”子网站组成:
- 我的网站
- index.html
- 网站图标
- 图片
- 文档
- index.html
- css
- 图片
- js
- ...
- 编辑
- index.html
- 图片
- js
- src
- ...
在哪里 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
,/etc/resolver
在 Mac 上或防火墙规则)以将您的 DNS 请求路由到您的应用程序。使用 DNS 的缺点是您需要在应用程序中构建一个类似于 pow.cx 的 DNS 服务器。 ,这似乎是不必要的复杂。
由于与系统配置发生冲突是不可避免的,我会投票支持在启动时或添加/删除目录时更改主机文件(通过 fsnotify 。)在关机时,您也可以清除添加的条目。
如果您希望将这些更改隔离到特定浏览器而不是进行系统范围的更改,您始终可以通过代理服务器运行您的应用程序,例如 goproxy并告诉您的浏览器使用该代理进行请求。例如,您可以在 Chrome 中通过其首选项或设置 --proxy-server
标志来执行此操作:
--proxy-server=<scheme>=<uri>[:<port>][;...] | <uri>[:<port>] | "direct://"
见 Chrome's network settings docs了解更多详情。
另外,如果您愿意使用浏览器配置,您可以使用 an extension根据需要处理请求。
关于go - 独立应用程序的本地子域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42730590/