How to add a slash at the end of the url?

Hi everyone ! :wave:

A colleague told me that our Workspace app doesn’t work with a proxy.

He investigated on the subject and he found one difference between the other apps and our own : a slash at the end of the url :
image

When he added a slash for our app, it worked !

before
image

after
image

Here is the <navigations> part from info.xml :

    <navigations>
        <navigation>
            <name>Workspace</name>
            <route>workspace.page.index</route>
            <icon>Workspace_white.svg</icon>
        </navigation>
    </navigations>

And I compared with other apps :

I don’t see the difference between my app and them.

There is the Spreed app use the boot function to register the navigation link : https://github.com/nextcloud/spreed/blob/0eeec23d49a354dcc23c0ec40cb0cd58e0823c8f/lib/AppInfo/Application.php#L348-L364 .

But, I reproduced the same code and I don’t get the slash at the end of the url for my app.

Hey. I see two things here that you could look into:

  1. The routes.php is also of interest. What is configured there?
  2. What reverse proxy are you using? I know that e.g. Apache is a bit picky about slashes as this is regex compared with the original URL in the browser.

Cheers
Christian

Hey Christian :slight_smile:

I’m using 2 routes to page#index :

<?php

return [
  		[
			'name' => 'page#index',
			'url' => '/',
			'verb' => 'GET',
		],
                // ...
		// The following route is there to prevent redirection to NC's general homepage
		// when reloading a page in the application (If we don't add it all pages that
		// don't have a route registered here redirect to NC's general homepage upon refresh)
		[
			'name' => 'page#index',
			'url' => '/{path}',
			'verb' => 'GET',
			'requirements' => array('path' => '.*'),
			'defaults' => array('path' => 'dummy'),
		]                
];

You can see the complete route here :point_right: https://github.com/arawa/workspace/blob/main/appinfo/routes.php

Hello Christian,
Thanks for your answer. Z4k’s colleague here, I’m working on the system side of our installations.

We are facing the trailing slash phenomenon independently from the proxy, even though the result is different. With nginx / Haproxy we can in the end reach the route, as a slash is added automatically.

Our question is more code-related in my opinion. As seen in Z4k’s screenshot, workspace is the only app in the appmenu to lack the slash and we’d like to match other apps in this regard.

Thanks,

I tried is a bit and I saw some strange effects. Unfortunately, I have to leave right now but can look at it later on.

Yes, of course !

Thank you for your help :pray:

We are waiting for what strange effects you’ve found :slight_smile:

This was very strange here on my dev machine. It looks a bit like there is some sort of caching involved…

  1. First, I could reproduce the issue that the URL ended inworkspace without /.
  2. I tried to break things intentionally by replacing the path to something like /abc. This did not change the URL in the frontend (Why :thinking:)
  3. I tried to change the path as well to no effect. (Now things are strange :face_with_spiral_eyes:)
  4. Adding a postfix to the catchall path. No changes. :face_with_raised_eyebrow:
  5. Changing the default navigation entry to workspace.page.indexfoo did in fact change the URL to the dashboard (ok :slightly_smiling_face:)
  6. Playing around with the postfixes and the urls in the routes.php resulted ultimately in a URL in the frontend ending in /. I cannot go back although I reverted the complete repo to the vanilla state. (no idea why I cannot reproduce anymore :face_with_peeking_eye: :worried:)

One point, I would at least consider good, probably even part of the problem: According to the the docs, you should only have one unique name for a route. You have in fact two pointing to page#index. You should add a postfix to either to make it unique. ( I suspect adding

'postfix' => 'catchall',

to the catchall block is the way to go.)

Maybe this even solved your problem directly.

Yes very strange !

I changed the / path by /abc and I have the same issue :thinking:

I added postfix on all my routes, I had an Exception, I deleted all postfixes, I refreshed the Nextcloud homepage and I had the slash at the end of the Workspace app url :exploding_head:

I think I will add the postfix in my second route :

		// The following route is there to prevent redirection to NC's general homepage
		// when reloading a page in the application (If we don't add it all pages that
		// don't have a route registered here redirect to NC's general homepage upon refresh)
		[
			'name' => 'page#index',
			'url' => '/{path}',
			'verb' => 'GET',
			'requirements' => array('path' => '.*'),
			'defaults' => array('path' => 'dummy'),
			'postfix' => 'catchall',
		]

If I understand, with postfix to catchall my final route is workspace.page.indexcatchall. But, the indexcatchall method doesn’t exist. I don’t know how it works :thinking:

Yes, I think, you should do this in any case.

One alternative might be (depending on your app’s layout), to get rid of the plain (first) route at all. The calendar app is doing something similar (on a deeper level though), see the routes of the calendar app. They allow to route different paths from Vue to the same Controller method.


There are two representations of routes to distinguish:

  1. in routes.php, there is the shorthand contoller#method to indicate a method to call
  2. There is a three-dot notation with app name.controller.route name.

The three-dot notation is used as the keys in a mapping (according to the docs, not checked in the source code). By default, the three parts can be derived from the app name and the two parts of the router’s method notation (№ 1 above). The values are most probably some internal structure that defines which class and which method to call.

As both routes in question call the very same controller method in the same app, the tree-dot notation is the same. So, you cannot distinguish between the two routes anymore and the linked route in info.xml is ambiguous.

To solve this, you can alter the three-dot notation by a postfix. (Please do not ask me, what happens if you put a dot there. Probably nothing but unchecked.) Nevertheless, now the mapping in the NC core has two entries that point both to the same controller method. That way you can distinguish the two routes in fact.

So, the internal structure in the core will be something like this (the values are just dummy and not the real game):

$knownRoutes = [
  // ...
  'workspace.page.index' => [
      'Controller' => \OCA\Workspace\Controller\PageConteroller.class,
      'method' => 'index'
      // ...
  ],
  'workspace.page.indexcatchall' => [
      'Controller' => \OCA\Workspace\Controller\PageConteroller.class,
      'method' => 'index'
      // ...
  ],
  // ...
];

You have now two ways to look at things:

  1. Given a three-dot notation, what is the corresponding URL? You need this to create the links in the navigation and potentially internally.
  2. Given the URL (split after .../apps/workspace), what controller and what method to use for serving? This is needed for every request to be handled. I guess there is a similar mapping involved to speed up the evaluation but I have not looked it up.

So, the postfix is only to make the three-dot notation unambiguous for further referencing. It does not effect the name of the app, the controller, or the method to use and handle the request.

Does this make it clearer?
Christian