Why my fileServer handler doesn't work? - http

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.

Related

How to import a module inside the Deno REPL?

Attempting to import a module in the Deno REPL results in the following error:
Uncaught SyntaxError: Cannot use import statement outside a module
at evaluate (rt/40_repl.js:60:36)
at replLoop (rt/40_repl.js:160:15)
I use the Node REPL to quickly test out code, almost on a daily basis. The ability to import external code without writing a script or dealing with temporary files is a huge convenience.
Why can't Deno use import statements outside of a module? Is it even possible to use external code in the Deno REPL?
Starting with v1.4.3, you can use top-level await in the REPL to dynamically import modules:
> const path = await import("https://deno.land/std#0.73.0/path/mod.ts")
> path.basename("/my/path/name")
"name"
If you also try to use import a from "a" in Node REPL, it will also throw the same error. Only require can be directly used to import modules in Node REPL.
For Deno, there is no built-in CommonJS loader. Therefore it does not even provide require for you to load stuff synchronously.
The technical reason of why static import cannot be used in REPL is that REPL is actually a script evaluation tool: instead of compiling what you write into an ES Module, they are treated as plain scripts and directly fed into the engine, in the way similar to <script> in the browser without turning on the type="module". (ES modules with static imports have the semantics of asynchronously loading dependencies and determining the "shape" of a module without even actually running it.)
To import modules in Deno REPL, you can use dynamic import(). Personally I sometimes do the following (loading is usually fast enough such that you will pretty much have mod value set before you continue using the mod in REPL):
$ deno
> let mod; import("./mod.ts").then(m => mod = m)
Promise { <pending> }
Check file:///[blah]/mod.ts
> mod
Module { a: 1, Symbol(Symbol.toStringTag): "Module" }

Static directory not getting served

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>

Golang net/http fileserver giving 404 on any pattern other than "/"

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/

Go server not serving files properly

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

ScalaJs PhantomJsEnv doesn't work when phantomjs is installed from npm

I am trying to use phantomjs as installed via npm to perform my unit tests for ScalaJS.
When I run the tests I am getting the following error:
/usr/bin/env: node: No such file or directory
I believe that is because of how phatomjs when installed with npm loads node:
Here is the first line from phantomjs:
#!/usr/bin/env node
If I change that first line to hardcode to the node executable (this involves modifying a file installed by npm so it's only a temporary solution at best):
#!/home/bjackman/cgta/opt/node/default/bin/node
Everything works.
I am using phantom.js btw because moment.js doesn't work in the NodeJSEnv.
Work Around:
After looking through the plugin source is here the workaround:
I am forwarding the environment from sbt to the PhantomJSEnv:
import scala.scalajs.sbtplugin.ScalaJSPlugin._
import scala.scalajs.sbtplugin.env.nodejs.NodeJSEnv
import scala.scalajs.sbtplugin.env.phantomjs.PhantomJSEnv
import scala.collection.JavaConverters._
val env = System.getenv().asScala.toList.map{case (k,v)=>s"$k=$v"}
olibCross.sjs.settings(
ScalaJSKeys.requiresDOM := true,
libraryDependencies += "org.webjars" % "momentjs" % "2.7.0",
ScalaJSKeys.jsDependencies += "org.webjars" % "momentjs" % "2.7.0" / "moment.js",
ScalaJSKeys.postLinkJSEnv := {
if (ScalaJSKeys.requiresDOM.value) new PhantomJSEnv(None, env)
else new NodeJSEnv
}
)
With this I am able to use moment.js in my unit tests.
UPDATE: The relevant bug in Scala.js (#865) has been fixed. This should work without a workaround.
This is indeed a bug in Scala.js (issue #865). For future reference; if you would like to modify the environment of a jsEnv, you have two options (this applies to Node.js and PhantomJS equally):
Pass in additional environment variables as argument (just like in #KingCub's example):
new PhantomJSEnv(None, env)
// env: Map[String, String]
Passed-in values will take precedence over default values.
Override getVMEnv:
protected def getVMEnv(args: RunJSArgs): Map[String, String] =
sys.env ++ additionalEnv // this is the default
This will allow you to:
Read/Modify the environment provided by super.getVMEnv
Make your environment depend on the arguments to the runJS method.
The same applies for arguments that are passed to the executable.

Resources