I'm trying to serve a folder in the root of my application called assets. I want all files and subfolders within there to be accessible through the url /details/.
fs := http.FileServer(http.Dir("assets"))
http.Handle("/details/", http.StripPrefix("/details/", fs))
I still get 404s for everything. Am I using StripPrefix incorrectly?
To be clear, suppose assets contained test.json. I want that to be accessible from the URL /details/test.json.
Per the above comments double check your paths, permission, user contexts etc.
If you are still stuck, start with this basic setup:
package main
import (
"log"
"net/http"
)
func main() {
fs := http.FileServer(http.Dir("/tmp/assets"))
http.Handle("/details/", http.StripPrefix("/details/", fs))
log.Fatal(
http.ListenAndServe(":8080", nil),
)
}
And test with curl etc.
$ find /tmp/assets
/tmp/assets
/tmp/assets/test.json
$ go run ./main.go
$ curl localhost:8080/details/
<pre>
test.json
</pre>
Related
Hello awesome stackoverflow community,
Apologies for the lame question.
I've been playing around with the net/http package in Go, and was trying to set an http.Handle to serve the contents of a directory. My code to the Handle is
func main() {
http.Handle("/pwd", http.FileServer(http.Dir(".")))
http.HandleFunc("/dog", dogpic)
err := http.ListenAndServe(":8080", nil)
if err != nil {
panic(err)
}
}
My dogpic handler is using os.Open and an http.ServeContent, which is working fine.
However, when I try to browse localhost:8080/pwd I am getting a 404 page not found, but when I change the pattern to route to /, as
http.Handle("/", http.FileServer(http.Dir(".")))
it is showing the contents of the current page. Can someone please help me figure out why the fileserver is not working with other patterns but only /?
Thank you.
The http.FileServer as called with your /pwd handler will take a request for /pwdmyfile and will use the URI path to build the filename. This means that it will look for pwdmyfile in the local directory.
I suspect you only want pwd as a prefix on the URI, not in the filenames themselves.
There's an example for how to do this in the http.FileServer doc:
// To serve a directory on disk (/tmp) under an alternate URL
// path (/tmpfiles/), use StripPrefix to modify the request
// URL's path before the FileServer sees it:
http.Handle("/tmpfiles/", http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("/tmp"))))
You'll want to do something similar:
http.Handle("/pwd", http.StripPrefix("/pwd", http.FileServer(http.Dir("."))))
you should write http.Handle("/pwd", http.FileServer(http.Dir("./")))
http.Dir references a system directory.
if you want localhost/ then use http.Handle("/pwd", http.StripPrefix("/pwd", http.FileServer(http.Dir("./pwd"))))
it will serve all you have into /pwd directory at localhost/
I'm using the ESP8266WebServer.h library for the ESP8266. Files can be served to a specific filename by using something like:
...
void example() {
sendFile(200, "text/html", data_example, sizeof(data_example));
}
...
webServer.on ("/example.html", example);
Once a file is served it cannot be updated by executing server.on ("/example.html", example2);.
How can a hosted file be removed (or updated to a blank file) so that it will return a 404 error ?
why not include a conditionnal logic in your example() function in order serve a 404 page when necessary ?
Hope it helps.
I've a simple folder :
Test/
main.go
Images/
image1.png
image2.png
index.html
In main main.go I just put :
package main
import (
"net/http"
)
func main(){
fs := http.FileServer(http.Dir("./Images"))
http.Handle("/Images/*", fs)
http.ListenAndServe(":3003", nil)
}
But when I curl on http://localhost:3003/Images/ or even I add to path file's name, it doesn't work.
I don't understand because it's the same as the reply given on
this subject
Can you tell me so that this does not work ?
You need to remove * and add extra sub-folder Images:
This works fine:
Test/
main.go
Images/
Images/
image1.png
image2.png
index.html
Code:
package main
import (
"net/http"
)
func main() {
fs := http.FileServer(http.Dir("./Images"))
http.Handle("/Images/", fs)
http.ListenAndServe(":3003", nil)
}
Then go run main.go
And:
http://localhost:3003/Images/
Or simply use:
package main
import (
"net/http"
)
func main() {
fs := http.FileServer(http.Dir("./Images"))
http.Handle("/", fs)
http.ListenAndServe(":3003", nil)
}
with:
http://localhost:3003/
The reason the request failed to return what you expected is because they did not match the pattern defined in the http.Handle(pattern string, handler Handler) call. The ServeMux documentation provides a description of how to compose patterns. Any request is prefixed matched from most specific to least specific. It appears as though you have assumed a glob pattern can be used. Your handler would have been invoked with requests to /Images/*<file system path>. You need to define a directory path like so, Images/.
On a side note, it is worth considering how your program gets the directory path to serve files from. Hard coding a relative means your program will only function within a specific location within the filesystem which incredibly brittle. You could use a command line argument to allow users to specify a path or use a configuration file parsed at runtime. These considerations make your program easy to modularize and test.
Dot in ./Images refer cwd current working directory, not you project root. For your server to work you must run it from Test/ directory, or address Images with absolute rooted path.
I am creating a SPA.
I am trying to respond all requests with index.html
(I handle routing on the frontend).
My directory structure look like this:
Backend
-- main.go
Frontend
..(some other files)..
-- index.html
Whole project is located in "C:\Go\Projects\src\github.com\congrady\Bakalarka"
My main.go file looks like this:
package main
import (
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "../Frontend/index.html")
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
When I run my main.go file (using go run), my localhost always responds with "404 page not found".
When I try to serve static content using fmt, everything works fine.
Please help, I'm stuck on this for a really long time and I can't get it to work.
Thanks
Be aware that if you hardcode relative paths in your source file, the directory which you are in when starting the app matters.
In the current configuration, make sure to start the app from the Backend directory, i.e.
C:\Go\Projects\src\github.com\congrady\Bakalarka\Backend,
NOT your apps root directory
C:\Go\Projects\src\github.com\congrady\Bakalarka
or
change the string in the main file to Frontend/index.html and run from
C:\Go\Projects\src\github.com\congrady\Bakalarka
I am writing application which will download some files by HTTP. Up to some point I was using following code snippet to download page body:
import network.HTTP
simpleHTTP (getRequest "http://www.haskell.org/") >>= getResponseBody
It was working fine but it could not establish connection by HTTPS protocol. So to fix this I have switched to HTTP-Conduit and now I am using following code:
simpleHttp' :: Manager -> String -> IO (C.Response LBS.ByteString)
simpleHttp' manager url = do
request <- parseUrl url
runResourceT $ httpLbs request manager
It can connect to HTTPS but new frustrating problem appeared. About every fifth connection fails with exception:
getpics.hs: FailedConnectionException "i.imgur.com" 80
I am convinced that this is HTTP-Conduit problem because network.HTTP was working fine on same set of pages (excluding https pages).
Have anybody met such problem and know solution or better (and simple because this is simple task which should not take more than few lines of code) alternative to Conduit library?
One simple alternative would be to use the curl package. It supports HTTP, HTTPS and a bunch of other alternative protocols, as well as many options to customize its behavior. The price is introducing an external dependency on libcurl, required to build the package.
Example:
import Network.Curl
main :: IO ()
main = do
let addr = "https://google.com/"
-- Explicit type annotation is required for calls to curlGetresponse_.
-- Use ByteString instead of String for higher performance:
r <- curlGetResponse_ addr [] :: IO (CurlResponse_ [(String,String)] String)
print $ respHeaders r
putStr $ respBody r
Update: I tried to replicate your problem, but everything works for me. Could you post a Short, Self Contained, Compilable, Example that demonstrates the problem? My code:
import Control.Monad
import qualified Data.Conduit as C
import qualified Data.ByteString.Lazy as LBS
import Network.HTTP.Conduit
simpleHttp'' :: String -> Manager -> C.ResourceT IO (Response LBS.ByteString)
simpleHttp'' url manager = do
request <- parseUrl url
httpLbs request manager
main :: IO ()
main = do
let url = "http://i.imgur.com/"
count = 100
rs <- withManager $ \m -> replicateM count (simpleHttp'' url m)
mapM_ (print . responseStatus) $ rs