Let's say this is the part where all routes are handled on a Node server with Angular front end. When the user enters the site URL, the server sends all the static files for the browser to render. However, I would like the client to handle certain routes instead of it going directly to the server.
For example, if I enter www.exemple.com/page2, a Get request is sent to the server but the route doesn't exist so the request just hangs there and ultimately resulting an error.
I want Angular to handle the routing instead of it going automatically to the server. I've only successfully got this to work on localhost where the Angular app is served from a different port than the one that the server listens to. Can anyone one tell me how to achieve this? Thanks a lot.
module.exports=function(app,dir){
app.use(express.json());
app.use(express.static(dir+'/dist/probeeshq'));
app.get('/',(req,res)=>{res.sendFile(path.join(dir));});
app.use('/auth', userAuth);
app.use('/api/me',userData);
app.use('/api/org',organization);
app.use('/api/messaging',messaging);
app.use('/api/search',search);
app.use(error);
}
This is what I have in Angular
const routes: Routes = [
{ path:'', component: HomeComponent },
{ path:'project_gaea', component:ProjectGaeaComponent},
{ path:'dashboard', component: DashboardComponent ,canActivate:[AuthGuardService]},
{ path:'explore', component:ExploreComponent, canActivate:[AuthGuardService]},
{ path:'create', component: CreateComponent },
{ path:'user/:id', component:UserProfileComponent},
{ path:'**', component: PageNotFoundComponent}
];
You can achieve this by implementing the Route feature that Angular has out of the box. After you implement this, you can then just use your back-end as an API.
So it turns out that I was supposed to serve the application like this:
app.use('/', express.static(dir));
And Express will let Angular handle all the routing after failing to match all the routes at the server side. dir is just the path were the Angular app is.
I have the same issue, with wildcard routes we can fix this. And client routes handling any unrecognised urls. Good from the user experience perspective no issues on that
like so
app.get("*", (req, res) => {
// send HTML files
});
But what about auditing wise, like a simple question like "if I send a unrecognised URL to server, it should give a 404 status code, instead of redirecting me to client and showing a 404 page or something"
Made a valid point, which doubted my knowledge on the web. But to resolve this we need to manually whitelist the client URL's in server, still figuring out myself, if any better solution please let me know.
Related
My website is a SPA built with Angular, but it uses SSR with Angular Universal to provide crawlable and social media sharing content.
All GET requests in my server are handled by Universal like this:
app.engine(
'html',
ngExpressEngine({
bootstrap: ServerAppModuleNgFactory,
providers: [provider]
})
)
app.set('view engine', 'html')
app.set('views', __dirname)
app.use('/', express.static('./dist', {index: false}))
app.use('/', expressStaticGzip('./dist', {
enableBrotli: true
}))
app.get('/*', (req, res) => {
res.render('./dist/index', {
req: req,
res: res
})
})
and my pages contents are provided by Angular Services POST requests built with the same queryParams of the requested url.
One example:
If the user visits the url https://mywebsite.com/products?page=1&itemsPerPage=12 (GET request by default), the Angular Universal app and the Angular Router dynamically build my page template and the products list is provided by a Service that triggers a POST request to this URL: https://mywebsite.com/request-products with the following params in body:
{
page: 1,
itemsPerPage: 12
}
Then the Universal App builds the template with some *ngFor directives to populate it before serving it to the client.
This approach makes all my pages visible to webcrawlers and I also get the benefits of a Single Page Application.
When I'm testing my app, I build my Angular app, both Browser and Server builds, and set my environment like this:
export const environment = {
production: true,
apiUrl: 'http://localhost:7070/'
}
and serves my app in localhost, it works perfectly, without errors. My POST requests, like mentioned before, are all handled perfectly. But when I try to set my apiUrl to 'https://mywebsite.com/' and serve my app also in localhost, to access directly my API hosted in Heroku, I just can't access my POST routes.
My node express server app in Heroku is configured to accept requests from other domains, I can access it normally in my localhost server, but when I try to access it through my Angular Universal server build, it just won't work.
I know that I have to use absolute URLS in my Universal Apps, and I'm doing it already, but it's not working.
Does anyone know what I have to do to access external APIs in my Angular Universal Apps via https?
Thanks!
I've found the problem, and it's something really simple.
It turns out that I must use 'www' in my absolute url, like this:
'https://www.mywebsite.com/'
Now everything works perfectly, both from my localhost and my heroku servers.
Thanks to everyone that took some time to read my question!
I have an express server. I have two routes as get methods.
app.get('/main',(req, res) => {
res.sendFile(`main.html`, {root: staticPath});
});
app.get('/signin', (req, res) => {
res.sendFile('signin.html', {root: staticPath});
});
I want to build my app as a single page react application. But before I let the user see this single page, I want to show a sign in, sign up screen. So when user clicks the sign in or sign up buttons, I want to send signin.html as response from the express server.
Here is my code on the browser from a react class
SignIn(){
axios.get('signin');
}
I can console.log() from the express route and verify that the code gets executed within the 'signin' route, but the html view doesn't change on the browser even though I send back a html file. How do I make it happen?
I'm by no means an expert, but here are my two cents. Instead of setting up your front end to receive an HTML file from the server, a more efficient approach would be the following.
Build the signup and login pages on the front end.
Set up routing between these pages.
Send the login/signup details from client to server via /login or /signup routes that you set up in Express. These details would usually be in the req.body object (make sure to install the bodyparser package from NPM).
You could then use JWTs to authenticate users and maintain sessions.
If you're looking for server-side rendering with React, here is an article for your reading pleasure :) Sorry if I made no sense.
I have two separate apps: one of them is my API in Node with Express, and the other is my front end in React with React Router.
Typically when doing smaller apps, you might have the server code colocated with your client code in the same repo, but in this case they are separate repos. I am trying to allow passthrough to React Router from Express if the route is not matched, and we traditionally do it like this:
app.get('*', function(req, res) {
res.sendFile(path.resolve(__dirname + 'dist/index.html'));
});
See the problem? I don't have the dist folder on my server, so I have no reference to the index.html available. The reason I broke out the repos is because I upload all the front end code to a CDN, and can just proxy the network requests to my API.
How do I allow the passthrough from Express to React Router if I don't have a file or path to resolve in the res.sendFile catch-all ?
A bit of a hack, but I realized that this would probably work and I tried it out and it does indeed. You can probably take this a step further and even extract the referrer from req.headers.
request("https://yourwebsite.com/index.html",(error, response, body) => {
res.send(body)
}
I need to query a database and I'm using create-react-app. The library to connect to the DB (pg-promise) does not work with Webpack and needs to be running on a Node server.
So I installed Express and have this:
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html'));
})
How can I load data from the database from the React pages? I though of using request but how can I make a request to my own server? And what should I add to the lines of code above? I think it would be something like:
app.get('/query/:querybody', (req, res) => {
// process and return query
})
Is this right? How can I make it work with a SPA?
Probably the most friction-free method would be to have a separate app.js or server.js along side your CRA application. You can use a tool like concurrently to run both your React app and the express app.
The trick is to serve your express app on a different port than the default :8080 that CRA serves on. Usually 8081 is a good choice, as it's a common convention to use port numbers that are close together when developing.
In your React app, you will need to make sure you use the full URL for the express endpoint: http://localhost:8081/query/...
On the server side you are going in the correct direction: you need to setup endpoint which will respond with data based on request. In you example you setup an endpoint for a GET HTTP request. If you will need to pass a complex request (for example add new record to database), consider using POST HTTP requests.
On the client side (in the browser) you will need a library that will assist you in sending requests to your server. I can recommend to try Axios (https://github.com/mzabriskie/axios). Usually if you omit protocol, server name and port, request will be sent to the server from which the page was loaded:
http:127.0.0.1:8001/api/endpoint => /api/endpoint
I have created web application in angular 2 for the client side and NodeJS with express framework for the server-side.
For the client side, I generated the project with angular-cli which runs on a lite-server, so my client and server are running on 2 different services.
I want to integrate ADFS authentication.
To implement the authentication, I am using passport-saml package.
There is a middleware in my server-side API which requires a user to authenticate.
The authentication process works fine when reaching the server directly (without the client).
However, I fail to access the API through the #angular/http.
I tried a simple GET request from the server (with the middleware in the end-point) and as a result I am getting the authentication page without redirection (I don't think it's the core problem, but the actual implementation is).
How should I properly implement the authentication when using separate services to the server and the client?
Hi I was also facing the same issue my angular project was hosted on 4200 port. and my node on 3000 port.
Its difficult to implement passport when we have 2 ports running.
step 1
make angular project static by doing an ng build to public folder .
make sure angular-cli.json has *"outDir": "../public",*
step 2
Now we can use the same node port to access angular roots please add below code in your node app.js
var path = require('path');
// Set Static Folder
app.use(express.static(path.join(__dirname, 'public')));
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname, 'public/index.html'));
});
This will enable your angular project accessible through node port.
step 3:
Now we can add the passport login button in the UI
and give the url twitter
THIS IS not explanatory means feel to ask me the doubts.
You are not giving much detail on what the failed response was when the client did the GET to the server. Was it a 400? 401? 404? 500? did you get a CORS error?
Why are you using GET for your login endpoint. You should be POSTing credentials right in the POST payload?
Anyway, in your angular2 code you should have an auth service with a login method. The login method should do something like ..
login(credentials) {
return http.post(your_server_url, payload);
}
you can then subscribe to the Observable returned by the login method and if all is good router.navigate to the home page or if it did not go well display login error messages.
Set separate urls for ui and server in ..src/environments/environment.ts
export const environment = {
production: false,
BASE_URL: 'http://localhost:4200',
API_BASE_URL: 'http://localhost:5000',
};
In node app.js
app.use('/', express.static('public'));
app.get('*', function (req, res) {
res.sendFile(path.join(process.cwd(), 'public', 'index.html'));
});
In your development environment, you should accomplish this by instructing your Angular CLI to proxy all requests to a backend server running on a separate port whenever you run "ng serve". Angular has good documentation on how to do this at https://angular.io/guide/build#proxying-to-a-backend-server. This will make your development process much faster, because you will not need to manually build your Angular application to test every code change.
When a production build is run, Angular will move the distributed files to the location specified in the "outputPath" property of Angular.json (by default set to "dist/<projectName>"). Your main production server will serve them appropriately from there as mentioned by #Lijo in their answer.