node-red-dashboard
node-red-dashboard copied to clipboard
Handle trailing slashes in the URL
closes #1476
Description
After some consideration, we will stick with slash-less URLs like /page1, and enforce that style with a 301 redirect middleware. It’s cleaner, SEO-friendly, backward-compatible, and avoids unnecessary rewrites.
Related Issue(s)
#1476
Checklist
- [x] I have read the contribution guidelines
- [x] Suitable unit/system level tests have been added and they pass
- [ ] Documentation has been updated
- [ ] Upgrade instructions
- [ ] Configuration details
- [ ] Concepts
- [ ] Changes
flowforge.yml?- [ ] Issue/PR raised on
FlowFuse/helmto update ConfigMap Template - [ ] Issue/PR raised on
FlowFuse/CloudProjectto update values for Staging/Production
- [ ] Issue/PR raised on
Labels
- [ ] Includes a DB migration? -> add the
area:migrationlabel
@robertsLando @Bond246 @rsp92028 Would the changes in this PR satisfy your issue?
The important part of the change is here: https://github.com/FlowFuse/node-red-dashboard/pull/1663/files#diff-76241199d5a97f1b00433a720ea273842ca6515d31015b1b24aee147e2a975bdR137-R143
In effect, what it does is:
- It checks if someone is trying to open a page with with a
/at the end - It then redirects (with a 301 status) to the correct page without the trailing slash.
@joepavitt one for you when you return
I am thinking this may be better handled in vue router?
I am unsure if redirecting will cause a loop with nginx
FWIW, if you enter a URL on the FF website without a trailing slash, it gets appended e.g. https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2 becomes https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/
i will test it when it is merged to the main release. Hope it work then i will be fine with it 💯
@Steve-Mcl @joepavitt - please see this thread - https://discourse.nodered.org/t/flowfuse-dashboard-2-0-issue-err-too-many-redirects/97107/6
I also saw this too_many_redirects loop when using my worldmap node (which sets up it's own endpoint also) but never figured out why...
@dceejay what endpoint is setup in your problematic instance?
from my testing, the middleware only affects /dashboard/... routes.
If your route is /dashboard/worldmap[/...] I can understand why (and makes the fix a little tougher!)
Also is a reverse proxy involved in your setup?
EDIT
Never mind. Routes added after Node-RED is setup are actually affected. Fix incoming
Hi - I was using it within an iframe so should was just set to /worldmap - but on one instance it went into that loop and wouldn't come out.. See also https://discourse.nodered.org/t/worldmap-dashboard-2-0-iframe-example-error-too-many-redirects/97123 for another user with same issue
For me the problem still exists.
I use traefik reverse proxy with an "addprefix" middleware that redirects the base-path "/" to "/dashboard/some-page".
Before the 1.24er dashboard-version there was just a problem with trailing slashes and traefik said it can't reach /dashboard/some-page/.
Now with the new version the browser-path is updated to /dashboard/some-page and traefik try to reach /dashboard/some-page/dashboard/some-page... obviously not working...
@Bond246 is this not an issue with your setup?
You state that "addprefix" middleware that redirects the base-path "/" to "/dashboard/some-page". so why would your configuration be appending "dashboard/some-page" to "dashboard/some-page"?
All the fix in this PR does is to redirect (with a 302 status code) from /dashboard/xxx/ to /dashboard/xxx (the redirect from dashboard/ to dashboard/first-page was an existing feature)
@Steve-Mcl the "addprefix" thing is really fine in treafik because if you just want to bypass some parts of the path all path-parts after the hardcoded prefix are to be seen in the browser. It just always adds the defined prefix.
In this situation here if the redirect status is mapped to the requesting browser as whole path of course you get appending paths. I actually try to ask the traefik community if there is another way but at the end of the day i just want to get the same behaviour like in the old nodered-dashboard the the /ui path where this "hack" worked really fine.
@Bond246 could you share your traefik config (sanitise where necessary).
@Steve-Mcl while it's inside kubernetes i try to copy what is need in my opinion. Node-Red Service:
apiVersion: v1
kind: Service
metadata:
name: nodered-test
namespace: nodered
spec:
clusterIP: 10.211.92.133
clusterIPs:
- 10.211.92.133
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- port: 1880
protocol: TCP
targetPort: 1880
selector:
app: nodered-test
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
IngressRoute with multible rules:
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
generation: 3
name: nodered-test
namespace: nodered
spec:
entryPoints:
- web
routes:
- kind: Rule
match: Host(`nodered-test.domain.de`)
services:
- kind: Service
name: nodered-test
namespace: nodered
port: 1880
- kind: Rule
match: Host(`nodered-test-page1.domain.de`)
middlewares:
- name: nodered-dashboard-page1
services:
- kind: Service
name: nodered-test
namespace: nodered
port: 1880
- kind: Rule
match: Host(`nodered-test-page2.domain.de`)
middlewares:
- name: nodered-dashboard-page2
services:
- kind: Service
name: nodered-test
namespace: nodered
port: 1880
Middlewares:
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
generation: 1
name: nodered-dashboard-page1
namespace: nodered
spec:
addPrefix:
prefix: /dashboard/page1
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
generation: 1
name: nodered-dashboard-page2
namespace: nodered
spec:
addPrefix:
prefix: /dashboard/page2
@Bond246 I am not up to speed on traefik but
You currently have two middlewares:
- nodered-dashboard-page1: adds prefix /dashboard/page1
- nodered-dashboard-page2: adds prefix /dashboard/page2
BUT:
- They just add a prefix → e.g.,
/becomes/dashboard/page1, - they don’t check the incoming path — they will blindly apply the prefix even if the request is already under
/dashboard/page1.
This is why you’re seeing things like:
/dashboard/page1 → /dashboard/page1/dashboard/page1 → /dashboard/page1/dashboard/page1/dashboard/page1 ...
You could try Redirect only:
//dashboard/dashboard/
But leave:
/dashboard/page1/dashboard/page2- anything under
/dashboard/*untouched.
Something like:
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: nodered-dashboard-redirect
namespace: nodered
spec:
redirectRegex:
regex: ^(/dashboard)?/?$
replacement: /dashboard/page1
permanent: true
Why I suspect addPrefix is not right here: addPrefix always prepends the string, no matter what the incoming path is. AFAIK, it doesn’t check if the path already has it so can lead to repeated prefixes. I think by switching to redirectRegex, you can conditionally match and rewrite only when necessary?
@Steve-Mcl you are correct, addPrefix always would add the path even if it already exists. But i also could got to google.com/foo/bar and would get 404 becaus it doesn't exist. So in my case the user doesn't know and doesn't have to know that there is something like /dashboard/xyz because he stays in his single specific space under /dashboard/page1 and thats it. Everything he needs is there.
But i will try to test redirectRegex which in this case would make the path that is added visible. Not so nice in my opinion like addPrefix but would fix the issue.
redirectRegex worked well like it should.
Not so nice like addprefix where the path was not provided to the browser url-bar but ok for what i want to do with it.