aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.42k stars 2.12k forks source link

Amplify Console 200 (Rewrite) fails on SPA React (Router) Application #2498

Closed wizawuza closed 5 years ago

wizawuza commented 5 years ago

Describe the bug When using the Amplify Console to build a project, the react router performs as expected when I click new links. When I hit Ctrl-R for refresh, it pushes me back to: https://..amplifyapp.com/index.html

The default "rewrites and redirects" is: Source address: /<*> Target address: /index.html Type: 404 (Not found)

So that makes sense.

When I change the rewrite to INSTEAD be: Source address: /<*> Target address: / Type: 200 (rewrite)

Things seem to work as expected initially. The page refreshes to a non-root page (e.g., if I'm at /user/account, a Ctrl-R will keep me there), but for some reason reason after a few minutes, I get an error in the console and the page is blank. I can change it back to a 404 (Not found) type of redirect, but that doesn't get me the desired behavior.

Note, the app works just fine with a local npm start command, as well as when using the CLI with "amplify publish", both on an S3 domain as well as a custom domain (via Route 53). I am not using a custom domain with the amplify console (yet) as I wanted to give it a shot to maybe help me with "dev-test-production" workflows.

Screenshots image

Desktop (please complete the following information):

Thank you!

wizawuza commented 5 years ago

In case it helps to debug.. After having this fail in Chrome per the above description, I then tried in MS Edge. That worked perfectly for a few minutes, afterwards it failed in a similar fashion.

Changing the type to 404 makes the website work again (although a Ctrl-R refresh always pushed it back to the root), but then afterwards switching it again back to 200 does not work, not even for a minute.

I tried clearing my cache in chrome in case that might have been an issue - no luck.

lisandrolan commented 5 years ago

I have a similar issue. I have the following paths example.com//bio or example.com/ and it is not redirecting.

@powerful23

swaminator commented 5 years ago

This is because your assets are not loading properly. We launched a feature to support regex based on this thread here: https://forums.aws.amazon.com/thread.jspa?threadID=294311&tstart=0

Try using regex in source. The format is </.../>. The following example will do rewrite to all files to index.html but except specific file extensions. source: </^[^.]+$|.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$)([^.]+$)/> target: /index.html type: 200

wizawuza commented 5 years ago

Even with the following rule: [ { "source": "</^[^.]+$|.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$)([^.]+$)/>", "target": "/index.html", "status": "200", "condition": null } ]

I still get the same error. This project works just fine when using amplify publish via the amplify CLI, and setting the S3 bucket's index document AND error document to "index.html" so I don't think it's an issue with my code.

elsenhuc commented 5 years ago

I have the same issue. Works perfectly on S3 with success:index.html and error:index.html - but I don't get the redirects to working state in amplify console

wizawuza commented 5 years ago

@elsenhuc The one I posted above: </^[^.]+$|.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$)([^.]+$)/> didn't work for me, but when I looked through the forum at: https://forums.aws.amazon.com/thread.jspa?threadID=294311&tstart=0 I found one that worked for another individual. Specifically: </^((?!\.(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$).)*$/>

As that one worked for me. I'd suggest you give that a go. I don't know regular expressions well enough to really know what the difference is between those two, so I can't help beyond that. I'll close this thread now as my issue is solved, but if that doesn't work for you please feel free to reopen.

elsenhuc commented 5 years ago

Hi, I went through that regex as well. Yes - it works on first view - but it fails when you use "querystring" parameters - at least for me. I have app.mydomain.com/events?noheader=1 and the ?noheader=1 piece is silently removed..making it impossible to parse

wizawuza commented 5 years ago

@elsenhuc Ah sorry to hear that. Are you using React? Would it be possible to switch to React Router and use their match and path parameters? That works for me at least.. Or is that too big of a rewrite in your current codebase? Sorry I don't have a more "backwards compatible" solution.

elsenhuc commented 5 years ago

hmmm..strange - In fact I am using react and ReactRouter already... let url = this.props.location.search; let params = queryString.parse(url); if (params.noheader) { ... }

wizawuza commented 5 years ago

I'd do it differently, namely: https://reacttraining.com/react-router/web/example/url-params namely, these lines: <Route path="/:id" component={Child} /> and then the function/component Child just below that.

That format of URL parameters is working for me with amplify console.

elsenhuc commented 5 years ago

That is something different...you are using a path (I do that already). The problem I am facing is a querystring parameter afterwards.

this piece works: <Route path="/events/:eventid" component={ViewEvent} /> but when you try URL/events/1234?param1=1&param2=2 that's a different story..

wizawuza commented 5 years ago

Can you change it so that URL should be /events/1234/1/2

and have the Route component look like: <Route path="/:id/:param1/:param2" component={Child} /> <Route path="/:id/:param1" component={Child} /> <Route path="/:id" component={Child} />

You may need some logic to make sure it doesn't show all 3 instances of the Child component every time, but otherwise I think that'll work.

elsenhuc commented 5 years ago

well..while this might be possible it's still...sort of a lame workaround :-) There must be a better way with regex

mike-casey-easyknock commented 5 years ago

This worked for me

source: </^((?!.(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$).)*$/>

target address: /index.html

type: 200 (Rewrite)

chrisfowler commented 5 years ago

@elsenhuc Did you ever get this issue resolve for ?querystrings. I too having trouble routing with querystring paramters. Getting stripped out. If I deploy using amplify publish from cli then no issues.

elsenhuc commented 5 years ago

The docs have been updated: https://docs.aws.amazon.com/amplify/latest/userguide/redirects.html but in the meantime I had changed my code and used a URL redirect inside react, rather than a querystring parameter - so I "avoided" it

artista7 commented 5 years ago

This worked for me too

source: </^((?!.(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$).)*$/>

target address: /index.html

type: 200 (Rewrite)

tylerjvollick commented 5 years ago

I have a SPA Create react app and am trying to get these redirects figured out... the following doesn't work at all. I get a 502 error. Any thoughts?

[
    {
        "source": "</^[^.]+$|\\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$)([^.]+$)/>",
        "target": "index.html",
        "status": "200",
        "condition": null
    }
]
tylerjvollick commented 5 years ago

I have a SPA Create react app and am trying to get these redirects figured out... the following doesn't work at all. I get a 502 error. Any thoughts?

[
    {
        "source": "</^[^.]+$|\\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$)([^.]+$)/>",
        "target": "index.html",
        "status": "200",
        "condition": null
    }
]

Ahh my bad. I needed my target to be "/" rather than "index.html". The following did the trick!

[
    {
        "source": "</^[^.]+$|\\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$)([^.]+$)/>",
        "target": "/",
        "status": "200",
        "condition": null
    }
]
javieraldape commented 5 years ago

I had the same problem and was able to solve it by adding the suggested redirects. The images and routes work correctly, however, the custom fonts are not loading.

When I leave the default redirects from the deployment, the correct fonts are shown but, when changing the source to </^((?!.(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$).)*$/> they stop loading.

Any Ideas?

wataruoguchi commented 5 years ago

It's not an amplify's issue. I'm using Vue.js, I assume React does similar. The router plugin of Vue.js has this documented nicely. It says all routes should fall to index.html: https://router.vuejs.org/guide/essentials/history-mode.html Hope it's helpful.

mgavaudan commented 5 years ago

@chrisfowler did you ever figure out how to keep the parameters with react and amplify?

adiaz-dev commented 4 years ago

The parameters that worked immediately for me were: "*</^((?!.(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$).)$/>**"

Without this rule the app was behaving incorrectly on the re-routing actions.

Regards,

r-moore commented 4 years ago

The rewrite is working for me at the first level (e.g. /login) but not if I have a second level of routing (e.g. /auth/login)

Two issues I've been struggling with:

  1. You can't navigate directly to /auth/login in the address bar (it's a path that React router is setup to handle but you never get redirected to /index.html so the react app doesn't load)
  2. It tries to load static resources (e.g. favicon.ico, or /static/js/main.js) from the subfolder (/auth/favicon.ico, /auth/static/js/main.js)

Has anyone else got amplify console working with this kind of app routing?

r-moore commented 4 years ago

I've managed to get it working with a 301 redirect for source: </(\/[^.]+$)/> to target: /

image

I'd rather use a 200 rewrite if anyone has any ideas how to make that work

fisheke commented 4 years ago

I got somewhere with my angular app (with routing) hosted in a subdirectory (quite similar to what react would be).

Solved with this:

    {
    "source": "</^[^.]+$|\\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf|map|json)$)(MY_SUBDIRECTORY\\/[^.]+$)/>",
    "target": "/MY_SUBDIRECTORY/index.html",
    "status": "200",
    "condition": null
    }
ilyador commented 4 years ago

Hi, I am having the same problem. Root works fine, any other path entered manually, redirects to index.html

Screen Shot 2020-01-11 at 20 36 16
scolestock commented 4 years ago

It's worth using the regular expression in the docs: https://docs.aws.amazon.com/amplify/latest/userguide/redirects.html

It includes "map", which will make sure your source maps are loading if needed.

DiegoArrieta commented 4 years ago

This worked for me

source: </^((?!.(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$).)*$/>

target address: /index.html

type: 200 (Rewrite)

Thanks! this worked for me!

tomyitav commented 4 years ago

Hi, how can I change Rewrites and Redirects in amplify console?

maxfelker commented 4 years ago

@tomyitav I used the above rule that @DiegoArrieta shared on 2/22 on a react app that I just created today with create-react-app. Here is my Amplify rule set:

Screen Shot 2020-05-19 at 4 17 55 PM

I added xml to the pattern to support serving public sitemap.xml files. Here's the snippet I used:

</^((?!.(xml|css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$).)*$/>

Good luck!

ShawnYcx commented 4 years ago

Hi, I'm having issues with react url param routes and it's giving out error on amplify.

Example routes with url params

<AsyncSearchResultsList path="search/:q" />
<AsyncSearchDetailedInfo path="search/user/:id" />

This is the error I'm getting image

On amplify I have these redirects setup image

I can't navigate to either of these routes and it works fine for other routes without parameters All of these routes are also working perfectly on localhost

Is there something I'm missing? I'm using Reach Router in my react project.

Update:

Figured what seemed to be part of it, the issue I was having was resolved. Amplify wasn't handling the Lazy loaded route components properly, data is flowing and the page is loading now after refactoring. But another issue came up, the page now displays blank whenever I navigate to those routes directly. I'm pretty sure it's an issue with Amplify's redirect rules. Still need help!

Caoimhin89 commented 3 years ago

I added </^((?!.(xml|css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$).)*$/> with a target of / and a rule of Rewrite 200.

This solution works for me for URLs that have one element after /, but anything beyond that still has the issue of resulting in a blank page.

For example:

I'm able to refresh the page while at example.com/account

If, however, I try to refresh the page while on example.com/account/edit I get a blank page again.

Has anyone figured out how to deal with this?

aqilusman45 commented 3 years ago

Anybody who is coming here to solve issues related gatsbyjs site with static and client site routes, I was able to solve navigation issues using these rules: image Note: first rule is for static content and the rule later is for handling client side routes, basically my Reach Router is in src/pages/app

Lasim commented 3 years ago

@elsenhuc: did you found a solution for the parameter problem? E.g.: mynicedomain.com/login?asd=12 I got the same issue with VueJS.

y-yeah commented 3 years ago

@elsenhuc The one I posted above: </^[^.]+$|.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$)([^.]+$)/> didn't work for me, but when I looked through the forum at: https://forums.aws.amazon.com/thread.jspa?threadID=294311&tstart=0 I found one that worked for another individual. Specifically: </^((?!\.(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$).)*$/>

As that one worked for me. I'd suggest you give that a go. I don't know regular expressions well enough to really know what the difference is between those two, so I can't help beyond that. I'll close this thread now as my issue is solved, but if that doesn't work for you please feel free to reopen.

Hi guys I realized this fix works except when one of the queries has the key called location. When a key exactly matches with "location", the page ends up showing Access Denied.

dbeck121 commented 2 years ago

I added </^((?!.(xml|css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$).)*$/> with a target of / and a rule of Rewrite 200.

This solution works for me for URLs that have one element after /, but anything beyond that still has the issue of resulting in a blank page.

For example:

I'm able to refresh the page while at example.com/account

If, however, I try to refresh the page while on example.com/account/edit I get a blank page again.

Has anyone figured out how to deal with this?

I have the same problem and I did not find a solution. I tried thousands of regex strings but no solution so far. I am super frustrated now. Working for houres on this problem now.

edit:

@Caoimhin89 in case you did not find a solution or it helps anyone.

Seems like I have a dirty fix at least for my react app:

[ { "source": "</^[^.]+$|\.(?!(css|ico|jpeg|gif|jpg|jpeg|js|png|txt|svg|woff|ttf|map|json)$)([^.]+$)/>", "target": "/", "status": "200", "condition": null }, { "source": "//<>", "target": "/<>", "status": "200", "condition": null }, { "source": "/<*>", "target": "/", "status": "404", "condition": null } ]

With this at least /result/1234 routes work in react

glothos commented 2 years ago

Having the same problem. When I go direct on root / it loads a blank page with Unexpected token < but if I type a correct route of the app like /auth/login it renders correctly.

image

Tried the solutions above and none worked.

charlie-ac commented 1 year ago

Having the same problem. When I go direct on root / it loads a blank page with Unexpected token < but if I type a correct route of the app like /auth/login it renders correctly.

image

Tried the solutions above and none worked.

For anyone who finds this in the future, I had the same problem and was able to resolve it by using

</^((?!.(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$).)*$/>

instead of

</^[^.]+$|.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$)([^.]+$)/>

It looks like that "Unexpected token '<'" error comes from the fact that the original regex was problematic and amplify was serving the contents of index.html even for urls like main.xxxxxxxx.js

kilian-v commented 11 months ago

Hello , I have the same error here but with a flutter web application. I have tried most of the proposed solutions but nothing works.

mrfrozen97 commented 4 months ago

I've managed to get it working with a 301 redirect for source: </(\/[^.]+$)/> to target: /

image

I'd rather use a 200 rewrite if anyone has any ideas how to make that work

Hello, I have similar issue with the redirect. I have a subdomain /GDPClock/USA I am using React router dynamic routes like "/GDPClock/:country" . THe amplify tried to load static files from /GDPClock/static/ instead of /GDPClock/ . How can I fix it.

mrfrozen97 commented 4 months ago

Also in the react router. I can only use one level of routing i.e. /Abc /bcd and not /abc/bcd. Why is the case? Is there a better alternative to React routing when using Amplify?

mrfrozen97 commented 4 months ago

Screenshot (6)

I got a stupid fix for sub-routes/nested routes not working in amplify.

Problem: /GDPClock works fine. /GDPClock/USA loads a blank white page.

The reason is that Amplify loads static resources from /GDPClock/static/js/abc.js but it should be /static/js/abc.js

Hack: I added a rule /GDPClock/static/<path1/<file redirects to /static/<path1/<file (301-permanant redirect) If you have many sub-routes u can use: "/<*>/static/<path1/<file" to "/static/<path1/<file" (301-permanant redirect)

I do not understand why does Amplify make it so complicated to just use some basic routing.

cortf commented 3 months ago

Hey I had a similar issue with my React/react-router-dom SPA deployment.

I encountered an issue where I could only access the home page directly. For example, visiting domain.com would load the page, and I could navigate to the /about section by clicking links. However, if I refreshed the page or, typed domain.com/about directly into the browser it would result in a 404 error. Although I added the correct rewrite rule, it still did not resolve the problem.

The solution that ultimately worked was adjusting the permissions of the S3 buckets related to my deployment. Specifically, I had to turn off the "Block all public access" setting. Once I made this change, the 404 issue was resolved, and I could access all pages directly.

miguelmobilat commented 3 weeks ago

Hola, tengo el mismo error aquí, pero con una aplicación web de Flutter. Probé la mayoría de las soluciones propuestas, pero nada funciona.

were you able to solve it?