Skip to content
This repository has been archived by the owner on Apr 8, 2020. It is now read-only.

Angular2 server-side rendering not working with matrix-formatted URLs #250

Closed
colltoaction opened this issue Aug 8, 2016 · 6 comments
Closed

Comments

@colltoaction
Copy link

Hi,

I have started a new angular2 project with the yeoman generator. I'm setting up the routing but I'm having an issue with the query parameters in matrix URL notation (angular's default) with server-side prerendering.

I'm trying to render http://localhost:5000/shop;page=1;genres=Alternative,Rock, but the = are being encoded and it breaks angular's parsing.

I'm posting here because the first message from the dotnet cli output seems to indicate there's an issue with how the URL is being sent to node from the aspnet side. Having said that, maybe I'm wrong and this is an issue with https://github.com/angular/universal, so let me know!

PS C:> dotnet run
Project MyProject (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
Hosting environment: Production
Content root path: C:\Users\............
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://localhost:5000/shop;page%3D1;genres%3DAlternative,Rock

If you need a repro I can work on that, but maybe you already know where and how the urls are being encoded and can easily spot the issue :).

Thanks!

@MarkPieszak
Copy link
Contributor

I do believe on the Universal-side, you shouldn't have a problem with these URLs, it may be being encoded before its sent to node since it believes it's a Querystring?

Not by a computer at the moment but I can try and take a look at the code tomorrow !

@colltoaction
Copy link
Author

  1. Run yo aspnetcore-spa and choose Angular2
  2. Replace home.ts with:
import * as ng from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@ng.Component({
  selector: 'home',
  template: require('./home.html')
})
export class Home {
  constructor(private route: ActivatedRoute) {
    this.route.params.subscribe((p: any) => console.log("params: ", p));
  }
}
  1. Go to /home;test=hello!
  2. See the logged params in the server (params: { 'test%3Dhello!': 'true' })
  3. Compare to the browser's (params: Object {test: "hello!"})

@SteveSandersonMS
Copy link
Member

Thanks for the clear repro info.

The issue comes down to the fact when ASP.NET gets incoming path segments containing reserved characters (like =), then HttpContext.Request.Path returns them with URL encoding, whereas JavaScript's location.pathname API returns them without URL encoding.

One workaround you could do right now would be to edit your boot-server.ts file and change this line:

ngCore.provide(REQUEST_URL, { useValue: params.url }),

to this:

ngCore.provide(REQUEST_URL, { useValue: decodeURIComponent(params.url) }),

However, I'm still discussing with colleagues on the ASP.NET team whether this is really a good idea and what would be the right way to reconcile ASP.NET's behaviour with Node/browser-based-JS. I want to get more feedback from people on whether the use of decodeURIComponent like that could constitute any security issue in any scenario we can imagine.

@colltoaction
Copy link
Author

Amazing! Please keep us posted if you come to any conclusion.

@SteveSandersonMS
Copy link
Member

SteveSandersonMS commented Aug 16, 2016

OK, I've pushed a change (c53bd8f) that should make the URL encoding (or lack thereof) consistent between server and client, so the problem should go away in your example at least. I'll publish updated NuGet packages shortly.

I'm still curious about how these matrix URLs are meant to work though. What is supposed to happen if an embedded key or value contains a space? It looks to me like this would be broken (not because of JavaScriptServices, but even just with a client-only app), because although the HTML5 pushState APIs let you set a URL with a space, if you tried to reload the page or navigate to it from somewhere else, Chrome at least will change the space to %20, and then location.pathname will see it as the characters %20 rather than a space. Does Angular 2 do something to fix this?

@colltoaction
Copy link
Author

colltoaction commented Aug 16, 2016

You're right, I'm getting %20 instead of spaces. Not only with matrix notation, but also with regular params. I'll have to do a replace I guess.

geirsagberg added a commit to geirsagberg/JavaScriptServices that referenced this issue Aug 17, 2016
* upstream/dev:
  Add ability to configure environment variables for Node instances, plus auto-populate NODE_ENV based on IHostingEnvironment when possible. Fixes aspnet#230
  Rename PrimeCache to PrimeCacheAsync (keeping older name as obsolete overload). Fixes aspnet#246.
  Prerenderer now passes original (unescaped) URL to Node - fixes aspnet#250
  In WebpackDevMiddleware, allow configuration of ProjectPath (implements aspnet#262)
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants