Angular 5 & Go Webservices - go

Angular 5 as a front end & backend as Golang and written Services in go
When the page is refreshed, the request is sent to the server which results in a page not found 404 error since the request bypasses the router in angular.
Ex: From Routing if we call /login we are able to display a page but if refresh the same it is showing as page not found 404.
Angular5:
const AppRoutes: Routes = [
{ path: '/', component: SignupComponent, pathMatch: 'full' },
{ path: 'login' , component: LoginComponent },
{ path: 'home' , component: VisitsComponent},
{ path: 'createavisit/:id', component: VisitComponent},
];
go:
http.Handle("/", http.FileServer(http.Dir("./angular/dist")))
http.HandleFunc("/register", RegisterHandler)
http.HandleFunc("/log", LoginHandler)
Could someone help me to fix this issue

In app module file where you import routing module add useHash:true parameter. For example: RouterModule.forRoot(routes, {useHash: true})

Related

Vue router.push() shows 404 component except browser is reloaded manually

With Laravel api resources, I have returned a desired path which I intend a user be redirected to once a record is successfully created.
The challenge now is that although it routes properly with Vuefrontend from the address bar on the browser, it loads the wrong component of 404 until I hit the refresh button on the browser. Is there a better way of fixing this without using window.location='path'?
Currently on my router file, I have the following.
import Vue from 'vue';
import VueRouter from 'vue-router';
import viewAsset from "./components/views/assets/viewAsset";
import NotFound from "./components/NotFound";
Vue.use(VueRouter);
export default new VueRouter({
routes: [
{ path: '/asset/:id/details', component: viewAsset, meta: {title: 'Asset Details ' }
},
],
mode: 'history'
})
And i'm using this.$router.push(response.data.links.self ); for the routing, where response.data.links.self is the path returned from the api

Vue.JS & Spring Boot - Redirect to homepage on 404

I am building a Vue.JS & Spring Boot app which I am running through a docker container. The dist folder for Vue is copied to resources/public path and served through the Spring Boot service.
I have set up routes using vue router, but all of these routes return 404 - Not found when entered directly into the browser (but work fine when accesses through the Vue app).
The vue router:
export default new Router({
mode: 'history',
routes: [{
path: '/',
name: 'home',
component: Home
},
{
path: '/result',
name: 'result',
component: Result,
props: true
},
{
path: '/result/:userid',
name: 'autoResult',
component: Result,
props: true
}
]
})
I need the /result/userid to not return a 404 - instead it should get the userid & render the result page. Is this possible to get to work?
Another thing I want to do is to redirect all 404-pages that are not mapped to any api / vue page to return to the start page. I have tried using the spring boot implements ErrorController but I cannot get the redirect to work.
Edit:
I tried adding the following Controller Advice:
#ControllerAdvice
public class WebConfig {
#ExceptionHandler(NoHandlerFoundException.class)
public String renderDefaultPage(NoHandlerFoundException e) {
return "classpath:public/index.html";
}
}
And the following properties:
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false
spring.mvc.static-path-pattern=/static/**
spring.resources.static-locations=classpath:public/static/
But when I try to access the frontpage now (or any other URL) i get the stackOverflowException and the server starts doing an infinite loop saying this:
2019-03-05 13:26:24.298 WARN 22044 --- [nio-8080-exec-1] o.s.web.servlet.PageNotFound : No mapping for GET /classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/classpath:public/index.html
Solved with the following code:
#Controller
public class RoutesController implements ErrorController {
private static final String PATH = "/error";
#RequestMapping(value = PATH)
public String error() {
return "forward:/";
}
#Override
public String getErrorPath() {
return PATH;
}
}
What's happening in your case is that Spring boot is taking the requests and, because nothing is mapped to the URL is giving you a 404. What you want to happen instead is to allow your Vue.js app to handle the unmapped URL's (IE, redirect any unmapped URL's to your index.html).
The first thing you need to do is adding this to your routes configuration in your router:
export default new Router({
mode: 'history',
routes: [{
path: '/',
name: 'home',
component: Home
},
{
path: '/result',
name: 'result',
component: Result,
props: true
},
{
path: '/result/:userid',
name: 'autoResult',
component: Result,
props: true
},
{
path: '*',
component: NotFound
}
]
})
Here we added an extra route as the last path (because routes are matched sequentially) that renders a component.
After that, you need to make Spring boot redirect every unmatched request to index.html, in order to do that, you want spring to throw an exception when it finds and unmapped route and in the handler of the exception redirect to your index.html.
First, add this line to your application.properties:
spring.mvc.throw-exception-if-no-handler-found=true
And add a ControllerAdvice to handle the thrown Exception, like this:
//In some controller or inside a #ControllerAdvice annotated class
#ExceptionHandler(NoHandlerFoundException.class)
String noHandlerFound(NoHandlerFoundException ex){
return "classpath:index.html";
}
Here you can find a little bit more info on making Spring boot redirect unmapped requests to your index.html
Unfortunately none of the above answers worked for me, luckily I've found this answer in another thread:
https://stackoverflow.com/a/59290035/1254782
It is simple and short and works like a charm for my use case, which might slightly differ from the original question, but I think it is quite similar. It might be useful for someone looking for serving vuejs SPA from spring boot backend.

Redirect routes not redirecting to the correct routes

I'm building a dashboard interface in Vue with Vue-router using history mode. Everything is working fine when you navigate to the individual routes cooresponding to the sections of the dashboard (e.g. '/employees/dashboard/main', '/employees/dashboard/orders/all'). I'm trying to set up some redirects in the web.php file using Route::redirect('/here', '/there'). I want everything to go to my dashboard landing page route: '/employees/dashboard/main'. Some routes properly redirect and some don't depending on if a '/' is at the end of the URI or not.
'/employees' redirects to '/dashboard/main' (incorrect)
'/employees/' redirects to '/employees/dashboard/main' (correct)
'/employees/dashboard' redirects to '/employees/dashboard/main' (correct)
'/employees/dashboard/' redirects to '/employees/dashboard/dashboard/main' (incorrect)
web.php (snippet)
//Employee Routes
//below route was also giving the same result but I left here to show that
//I've also tried it.
//Route::redirect('/employees', '/employees/dashboard/main');
Route::group(['prefix' => 'employees'], function() {
Route::redirect('', 'dashboard/main', 308);
Route::redirect('/', 'dashboard/main', 308);
Route::redirect('/dashboard', 'dashboard/main', 308);
//catch-all route so vue router routes don't throw 404
Route::get('/dashboard/{any}', 'EmployeeController#showDashboard')
->where('any', '.*')
->name('employee.dashboard');
});
employee-dashboard.js (snippet)
const router = new VueRouter({
mode: 'history',
linkActiveClass: 'active',
routes: [
{path: '/employees/dashboard/main', component: Main},
{
path: '/employees/dashboard/orders',
component: Orders,
redirect: '/employees/dashboard/orders/active',
children: [
{path: 'all', component: FilteredOrders},
{path: 'active', component: FilteredOrders},
{path: 'completed', component: FilteredOrders}
]
}
]
});
const dashboard = new Vue({
el: '#dashboard',
router
});
Then in dashboard.blade.php I have my router-links and router-view set up.
Any help will be greatly appreciated. Thanks.
Edit:
What's even more strange is when I comment out all of the Route::redirect entries in web.php, run php artisan route:clear, and restart php artisan serve, then go to /employees, it still redirects me to the wrong route (/dashboard/main).
I've found the cause of the bad redirects. The browser caches redirects and for some reason will use that rather than the updated redirect route in the routes/web.php file. To clear this cache in Firefox: Go into the history menu and right click on one of the pages from your laravel project, then click "Forget about this site". It will now use the updated redirect routes in your routes file.
I've also changed the redirect to: Route::redirect('/employees', '/employees/login'); since I'm using Laravel's Auth scaffolding and have it set up to redirect to the main page of my dashboard after logging in.
Here is where I found this solution:
https://superuser.com/questions/467999/clear-301-redirect-cache-in-firefox#661767

Vue Router and Vuex

I have 2 questions.
1. How can I catch undefined routes and redirect to 404 page?
2. How I can use Vuex actions to get data from api? I know that vuex mutations must be sync and actions async. But I can get data with mutations and can use then promise. but can't in actions or I do anything mistake. Please give me beautiful example for that(component type). I use vuex in laravel mix in Laravel project. Thanks...
Generally speaking, you shouldn't be getting undefined routes if you're defining all of the routes within an app. You can define a redirect in your routes configuration as such:
[
{
path: 'admin/posts/list',
name: 'post-list',
},
{
path: 'admin/posts',
redirect: 'admin/posts/list'
}
]
// you can also redirect to a named route instead
// of a path like this:
{
path: 'admin/posts',
redirect: { name: 'post-list' }
}
If you wanted to do a "catch all" that grabs any paths not matched and redirect to your 404 component/view, then you could do it like this:
{
path: '*',
redirect: '/404'
}
Make sure that is at the bottom of your routes definition as the last route because it will catch any routes in the tree it is above.
As for your question about mutations/actions, asynchronous API requests like fetching data from an API only every happen within actions when you're using Vuex.Taken from the documentation on actions:
actions: {
actionA ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
}

MVC6 routing to single-page application without losing 404

I'm writing a single-page application with angular2 and MVC5. I'm new to both, though, and I'm having trouble with the routing.
I'd like to match URLs as:
/ -> go to my index page, which bootstraps angular
/api/{controller}/{id?} -> REST API
/{*anythingelse} -> if a file exists there, return it as static content; otherwise if angular can route it, have angular route it; otherwise return 404.
The second point's easy enough, and I can get the client-side routing working if I'm willing to give up 404 returns, but I can't seem to reconcile it all.
It seems like this ought to work:
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "api",
template: "api/{controller}/{id?}");
routes.MapRoute(
name: "spa",
template: "{*anythingelse}",
defaults: new { controller = "Home", action = "Index" });
});
and:
#RouteConfig([
{ path: "/", name: 'Splash', component: SplashView },
{ path: '/accounts/login', name: 'Login', component: LoginView },
{ path: '/accounts/register', name: 'Registration', component: RegistrationView },
{ path: '/home/...', name: 'Home', component: HomeView },
])
But that just serves Index.cshtml for every request that isn't a static file.
I feel like this must already be a solved problem, but I haven't been able to find anything online about it. How does one do this properly?
I'm using "HTML5"-style paths rather than hash-style.
So there are two ways to go about doing it. If you are using the HashLocationStrategy I would strongly encourage you to do this on your server side implementation as I have found it much easier to deal with.
Otherwise you could make your own RouterOutlet component that handled the exceptions. I am not 100% clear on how you could get it to work with your RouterConfig as I have not delved that deep into the routing aspect, but I bet you could see if there exists a route then go there otherwise 404 error. Here is my code that deals with seeing if a user is logged in with Json Web tokens.
import {Directive, Attribute, ElementRef, DynamicComponentLoader} from 'angular2/core';
import {Router, RouterOutlet, ComponentInstruction} from 'angular2/router';
#Directive({
selector: 'router-outlet'
})
export class LoggedInRouterOutlet extends RouterOutlet {
publicRoutes: any;
private parentRouter: Router;
constructor(_elementRef: ElementRef, _loader: DynamicComponentLoader,
_parentRouter: Router, #Attribute('name') nameAttr: string) {
super(_elementRef, _loader, _parentRouter, nameAttr);
this.parentRouter = _parentRouter;
}
activate(instruction: ComponentInstruction) {
if (!localStorage.getItem('jwt') || !tokenNotExpired('jwt')) {//Public Routes does not work with Hash Location Strategy, need to come up with something else.
// todo: redirect to Login, may be there is a better way?
if(localStorage.getItem('jwt')){
localStorage.removeItem('jwt');
}
this.parentRouter.navigate(['Login']);
}
return super.activate(instruction);
}
}
As you can see I handle my checking for the Token, and if they don't have a token they can only go to my login page. Then in your app.component or your bootstrapped component just use this as your router-outlet instead of the original.
Sorry I can't be more helpful but I hope this gets you pointed in the right direction!
I think you're looking for a regex route constraint:
routes.MapRoute("app", "{*anything}",
new { controller = "Home", action = "Index" },
new {anything = new RegexRouteConstraint("^(?!api\\/).+") });
This will prevent your catch all route from mapping to any request that begins with "api/"

Resources