U.M*_*ral 9 dns proxy reverse-proxy go
我有一个网站,由三个较小的"独立"子网站组成:
doc使用Hugo ::一个快速而现代的静态网站引擎创建的网站在哪里,editor是mxgraph的Graphditor示例 ; 其余的文件制作一个手工制作的登陆页面.
除了部署到任何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)
}
这些只是片段.一个完整的例子是这样,这是在评论由@ Steve101引用.
但是,现在,我不知道systemDefaultHandler是什么.那并没有解决.
除此之外,@ faraz建议使用goproxy.我认为这HTTP/HTTPS transparent proxy是我正在寻找的默认处理程序.但是,使用一个包来做那件事对我来说似乎太过分了.我可以使用内置资源实现相同的功能吗?
不幸的是,没有非常简单的方法可以通过 Go 来做到这一点。您需要像 dnsmasq 一样拦截系统的 DNS 请求,这不可避免地需要对系统 DNS 配置(/etc/resolv.conf在 Linux 中、/etc/resolverMac 上或防火墙规则中)进行一些修改,以将 DNS 请求路由到您的应用程序。使用 DNS 的缺点是您需要在应用程序内构建一个类似于pow.cx 的DNS 服务器,这似乎不必要地复杂。
由于系统配置的混乱是不可避免的,所以我投票支持在启动时或添加/删除目录时(通过fsnotify )更改主机文件。在关闭时,您也可以清除添加的条目。
如果您希望将这些更改隔离到特定浏览器而不是进行系统范围的更改,您始终可以通过像goproxy这样的代理服务器运行您的应用程序,并告诉您的浏览器使用该代理来处理请求。例如,您可以在 Chrome 中通过其首选项或设置标志来执行此操作--proxy-server:
--proxy-server=<scheme>=<uri>[:<port>][;...] | <uri>[:<port>] | "direct://"
有关更多详细信息,请参阅Chrome 的网络设置文档。
另外,如果您愿意对浏览器配置进行太多处理,则可以仅使用扩展程序来根据需要处理请求。