2017-07-02 191 views
0

我在reactjs項目中使用react-router和browserHistory的pushState。該項目讓用戶創建一個創建新路徑的註釋。爲了提供這種類型的網站,我需要爲靜態內容以外的每個路徑提供相同的HTML文件。所以我的nodejs代碼看起來像這樣。如何使用Go來動態創建URL路徑?

// Serve the static content 
app.use('/static/css/', express.static(path.join(__dirname, '../../react-ui/build/static/css'))); 
app.use('/static/js/', express.static(path.join(__dirname, '../../react-ui/build/static/js'))); 
app.use('/static/media/', express.static(path.join(__dirname, '../../react-ui/build/static/media'))); 
app.use('/static/img/', express.static(path.join(__dirname, '../../react-ui/build/static/img'))); 
app.use('/img/', express.static(path.join(__dirname, '../../react-ui/build/img'))); 

// Serve the same HTML file to everything else 
app.use('*', express.static(path.join(__dirname, '../../react-ui/build'))); 

我沒有看到Go FileServer的任何通配符支持。目前我使用Go代碼提供的所有靜態頁面與此類似。

package main 

import (
    "net/http" 
) 

func init(){ 
    fs := http.FileServer(http.Dir("web")) 
    http.Handle("/", fs) 
    http.Handle("/static-page-1/", http.StripPrefix("/static-page-1/", fs)) 
    http.Handle("/static-page-2/", http.StripPrefix("/static-page-2/", fs)) 
    http.Handle("/static-page-3/", http.StripPrefix("/static-page-3/", fs)) 
} 

是否有可能成爲內容動態生成與進入服務器的URL路徑?

如果處理方法支持的變量,那麼我寫這樣

fs := http.FileServer(http.Dir("web")) 
http.Handle("/static/", fs) 
http.Handle("/{unknownUserPath}", http.StripPrefix("/{unknownUserPath}", fs)) 

{} unknownUserPath的代碼將任意路徑,在用戶鍵入沒有受到/靜態/路徑。

這裏的圍棋項目結構

enter image description here

下面是基於@putu服務器回答

package main 

import (
    "net/http" 
    "strings" 
) 

func adaptFileServer(fs http.Handler) http.Handler { 
    fn := func(w http.ResponseWriter, req *http.Request) { 
     staticIndex := strings.Index(req.URL.Path, "/static/"); 
     imgIndex := strings.Index(req.URL.Path, "/img/"); 

     if staticIndex == -1 && imgIndex == -1 { 
      fsHandler := http.StripPrefix(req.URL.Path, fs) 
      fsHandler.ServeHTTP(w, req) 
     } else { 
      fs.ServeHTTP(w, req) 
     } 
    } 
    return http.HandlerFunc(fn) 
} 

func init() { 
    fs := http.FileServer(http.Dir("web")) 
    http.Handle("/", adaptFileServer(fs)) 
} 

回答

1

如果您想要將URL模式爲/*的靜態內容提供給特定目錄,請使用jeevatkm提供的答案。

如果你需要稍微定製的版本,你需要一種適配器的是,URL路徑映射到靜態文件處理程序(http.FileServer)。示例代碼看起來像:

package main 

import (
    "log" 
    "net/http" 
    "regexp" 
) 

func helloHandler(w http.ResponseWriter, r *http.Request) { 
    w.Write([]byte("Hello world!")) 
} 

func adaptFileServer(fs http.Handler, mux http.Handler) http.Handler { 
    fn := func(w http.ResponseWriter, req *http.Request) { 
     //Use your Path matcher here. 
     //For demonstration, REGEX match is used 
     //and it's probably not the most efficient. 
     staticRegex := regexp.MustCompile("^/static-page-[0-9]+/") 
     if matches := staticRegex.FindStringSubmatch(req.URL.Path); matches != nil { 
      log.Printf("Match: %v, %v", req.URL.Path, matches[0]) 
      fsHandler := http.StripPrefix(matches[0], fs) 
      fsHandler.ServeHTTP(w, req) 
     } else if mux != nil { 
      log.Printf("Doesn't match, pass to other MUX: %v", req.URL.Path) 
      mux.ServeHTTP(w, req) 
     } else { 
      http.Error(w, "Page Not Found", http.StatusNotFound) 
     } 
    } 
    return http.HandlerFunc(fn) 
} 

func init() { 
    //Usual routing definition with MUX 
    mux := http.NewServeMux() 
    mux.HandleFunc("/hello", helloHandler) 

    //"Dynamic" static file server. 
    fs := http.FileServer(http.Dir("web")) 
    http.Handle("/", adaptFileServer(fs, mux)) 
} 

func main() { 
    log.Fatal(http.ListenAndServe(":8080", nil)) 
} 

在上述適配器例如,如果請求路徑匹配到特定圖案/static-page-*/在上面的例子中),它會被傳遞到http.FileServer。如果不匹配,並且指定了多路複用器,則將調用mux.ServeHTTP。否則,它將返回404錯誤。

如果您需要其他匹配規則,只需更改regex模式(或使用您的自定義匹配器)。

注:
請不要使用FileServermux相同的處理程序實例。例如,當您撥打http.Handle時,它使用http.DefaultServeMux來處理路由。如果通過http.DefaultServeMux作爲adaptFileServer的第二個參數,則可能會導致無限遞歸。

+0

謝謝!我能夠讓文件服務器在沒有多路複用服務器對象的情況下工作,但如果我想添加任何服務,那麼我需要使用它。我將我用的代碼添加到了我的問題中 – sissonb

0

http.FileServer是不錯的選擇從目錄提供靜態文件和它的子目錄。

func main() { 
    http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) 

    log.Println("Listening...") 
    if err := http.ListenAndServe(":8080", nil); err != nil { 
    log.Fatal(err) 
    } 
} 

它將通過http://localhost:8080/static/<path-to-file>服務/static/*目錄下的所有文件和子目錄。

因此,設計您的目錄結構並通過一個或多個文件服務器處理程序進行映射。


編輯:

由於要求在註釋。從根目錄和底部提供靜態文件。

http.Handle("/", http.StripPrefix("/", http.FileServer(http.Dir("web")))) 

這意味着web/*下文件將從根/送達。

+0

這部分工作,但我想要做的就是這樣,'http.Handle(「/ *」,http.StripPrefix(「/ *」,fs))'*將是一個通配符。 – sissonb

+0

好吧,我明白了。只是爲了澄清你的意思是根'/'而下面是爲靜態文件提供服務? – jeevatkm

+0

除了答案,請看看。 – jeevatkm