server.transfer in express node js - c#

I would like to transfer request one server to another server. Like server.transfer in C#. I know we can go for response.redirect or response.writeHead methods in nodejs but these have a client side (browser) interaction.
In my case, the user should not see where I am redirecting as it should server to server call.
As of now, I have achieved by unirest.
app.get('/home', function(request, response) {
unirest.get("www.example.com/userdetails").end(function (res) {
response.send(res.body)
});
});
But am expecting same in express. suggestions welcome.

You can do that inside express with http.request method, but you can also use higher level packages, like request and axios.

I created an express module to add req.transfer(path, preserveData) to all routes. This allows you to internally transfer requests without sending a redirect to the client:
var express = require('express');
var requestTransfer = require('express-request-transfer');
var app = express();
app.use(requestTransfer); // adds req.transfer method to all routes
// route 1
app.get('/api/time', function(req, res){
res.send(new Date());
});
// route 2
app.post('/', function(req, res){
// transfer without form/query data
req.transfer('/api/time');
// transfer with incoming form/query data
// req.transfer('/api/time', true);
});
It functions the same as Server.Transfer from C#. Source code on GitHub

Related

How to redirect to a new URL after authentication [duplicate]

I have created a to-do list app using Node, Express and Mongoose:
To delete a task, the user hits the cross button on the right hand side. This sends a POST request with the task ID to the /delete_task endpoint. The router for this endpoint is /routes/delete_task.js:
var express = require('express');
const Task = require('../models/task');
var router = express.Router();
express.json();
router.post('/', async (req, res, next) => {
const deleted_task = await Task.findByIdAndDelete(req.body.taskID);
console.log('Deleted task: \n', deleted_task);
res.redirect('..');
}
);
module.exports = router;
The router performs a findByIdAndDelete, and then redirects to the home directory. The router for the home directory renders a view of all the existing tasks in the collection, and looks like:
var express = require('express');
const Task = require('../models/task');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
Task.find({}, function (err, result) {
if (err) {console.error(err)};
if (result) {
return res.render('index', {title: 'To-do list', tasks: result})
};
});
});
module.exports = router;
My problem is that when deleting a task, the findByIdAndDelete successfully deletes the task, but this is not reflected in the redirected home page. The deleted task only disappears once I refresh the page. This suggests that it's some kind of async issue, and that the redirect is happening before the findByIdAndDelete query has finished executing.
To address this, I have made the router.post() callback an async function and am using await on the findByIdAndDelete, and I have also tried placing the res.redirect('..') in a callback function of the findByIdAndDelete, which also does not fix the problem:
router.post('/', (req, res, next) => {
Task.findByIdAndDelete(req.body.taskID, (err, result) => {
if (err) {
console.error(err)
};
if (result) {
console.log(result)
};
res.redirect('..');
});
});
I have looked for other questions on stackoverflow, all of which seem to suggest that this is an async issue caused by the redirect happening before the query has finished executing. The suggested solutions I have found were to make the router.post(...) callback an async function and await the result of the Mongoose query, or to place the res.redirect('..') in the callback of the findByIdAndDelete so that the redirect happens after the query has finished executing. I have tried both of these but the problem remained.
The only other thing I can think of is that I am trying to redirect from within a POST request, and I don't know if this is legit. It seems to work fine looking at the log (see last 2 lines where the GET request to / follows the POST request to /delete_task):
New task submitted: cake
New task created successfully: cake
POST /new_task 302 29.747 ms - 46
GET / 200 4.641 ms - 1701
GET /stylesheets/style.css 304 0.849 ms - -
GET /javascripts/delete_task.js 304 0.479 ms - -
Deleted task:
{
_id: new ObjectId("636a993ca0b8e1f2cc79232a"),
content: 'cake',
completed: false,
__v: 0
}
POST /delete_task 302 10.358 ms - 24
GET / 200 3.867 ms - 1348
This is where I've hit a brick wall and I can't see what might be causing the issue. Really appreciate any help or suggestions anyone might have - cheers.
I don't think this is a problem with asynchronousness, because you wait properly before responding to the POST request.
But the res.redirect makes sense only if hitting the cross button navigates from the To-do list page to the /delete_task page and from there back, by virtue of the redirection. This would be possible only with an HTML <form> element that is submitted upon hitting the button.
Is that how you have implemented it? You say that you "send a POST request", but is this through a <form>, or rather through an axios.post or a similar Javascript method? In the latter case, the following would happen:
The Javascript client sends the POST request and the deletion is carried out on the database.
The Javascript client receives a redirection response and sends the GET request.
The Javascript client receives the HTML page for the to-do list as response, but does nothing with it.
In other words: the To-do list page would not be reloaded by this axios.post request. If you want this to happen, don't respond to the POST request with a redirection, but simply with 200 OK, and have the Javascript client execute location.reload() when it receives this response.

PuppeteerSharp and Page Level Proxies

I know this is possible using Puppeteer in js, but I'm wondering if anyone has figured out how to proxy on a page level in PuppeteerSharp (different proxies for different tabs)?.
it seems I can catch the request, but I'm not sure how to adjust the proxy.
page.SetRequestInterceptionAsync(true).Wait();
page.Request += (s, ev) =>
{
// what to do?
}
Edit
I am aware that I can set the proxy at the browser level like so;
var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = false,
Args = new[] { "--proxy-server=host:port" }
});
var page = await browser.NewPageAsync();
await page.AuthenticateAsync(new Credentials() { Username = "username", Password = "password" });
But this is not what I'm trying to do. I'm trying to set the proxy for each page within a single browser instance. I want to test lots of proxies so spawning a new instance of the browser just to set the proxy is too much overhead.
You can use different browser instances for each logical instances. I mean instead of trying to set different proxy for each page/tab with different proxy just create new browser instance and set proxy via launch args.
If this solution doesn't fit your needs, check this question. There is library for NodeJS which give ability to use different proxy per each page/tab. You can check that library source code and implement same things inside your C# application.
That library is using very simple method. Instead of sending requests via puppeter's browser/page library send request via nodejs http tools. It can be done by using method page.setRequestInterception. So library intercept each request from page, after that gather data and send request via http tools. I used C# a long time ago. So maybe I am wrong, but you can try to use HttpWebRequest or something similar. After you get result you should use method request.respond and pass response results there. In this way you can put any kind of proxy inside your application. Check here code of library.

HttpContext Session resets after client side request only

Overview
I have an ASP.net core API that has one controller. There are two relevant methods. The first Is LoginGet, which takes in a long token through the URL. Once the token is parsed through a separate core authentication API, the long token is stored like so:
Request.HttpContext.Session.Set(longToken, Encoding.UTF8.GetBytes(stringResult));
Then, the API generates a GUID for the user to store in session storage. After the user retrieves that GUID, they can pass it through GetAll, which filters through a database only picking out the data that correlates to the user that passed through the GUID. That means the API has to take the GUID, and compare it to the long token that was stored in session at the LoginGet request.
The Good
It all works when I hit these request from my localhost. Here is the series of request I make:
First I hit LoginGet():
http://localhost:5000/api/picker/login?token=ljadsljdaslkjsdfljkljgsdfkjgfFSDDFSsakgfjhdfkhdsfFDAS/asdfkjhdsf+sfdhjkfdsa
That returns a GUID like this:
58fa0fec7726433da47dce966b313c69
Then I hit GetAll():
http://localhost:5000/api/picker?ath=58fa0fec7726433da47dce966b313c69
That returns my json data
The Bad
The above example works! So what's wrong? When I do those exact same request (but with a different random GUID) from my Angular 2 application which is being served locally on a different port (http://localhost:3000/), LoginGet() is successful and returns a new GUID, but when I make the second request, GetAll(), immediately after the first, while debugging, I see that the Session has changed on the API, as if I were doing the second request from a new browser, or I just cleared my cookies.
This was not the case when I was simply making these calls from the browser, myself, manually. I have my request being console logged on the front end, and I get the exact same request URLs as I explained above.
I feel like this has to be an issue with how I am making the request on the front end. But I don't see how that could be the case. Even with routing, my session should remain the same.
Here are the two request methods relevant to this issue (Angular 2)
public Get(): Observable<{}> {
let newQuery = 'http://localhost:5000/api/picker?ath=' + sessionStorage.getItem('user.token');
return this.http.get(newQuery).map(this.extractData)
.catch(this.handleError);
}
public GetLogin(longToken: string) {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
let body = JSON.stringify({ password: longToken });
return this.http.get('http://localhost:5000/api/picker/login?token=' + longToken);
}
The order of operations for those request go like so:
1. A longToken is given by the user
2. The long token is passed to GetLogin(longToken)
3. The result is returned and immediately subscribed to.
4. On success, the generated GUID from the API is set in sessionStorage
5. The appilication routes to a different component (this.router.navigateByUrl('/library?pvy=me'))
6. After routing, in library component ngOnInit, Get() is called and uses the GUID stored in sessionStorage.
7. The result is immediately subscribed to in the library component.
That's It
What could be happening in my Angular 2 App that changes the session on the API? Or am just completely lost on how Sessions work in .net core?
What I found out is that when hitting the API externally, from the browser Address bar, Headers were being generated automatically. Which means the cookies from the session could be stored there. When I was calling my Get() method from the angular 2 App, I wasn't adding a header to my request, so the API assumed it was a new session.
My new Get() method on the angular 2 app:
public Get(): Observable<{}> {
let newQuery = 'http://localhost:5000/api/picker?ath=' + sessionStorage.getItem('user.token');
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.get(newQuery, options).map(this.extractData)
.catch(this.handleError);
}

Edge + Express + SQL Server unexplainable StackOverflow

So I've been banging my head against a wall trying to figure this one out. A StackOverflow is crashing my server whenever I try to retrieve data from SQL Server using several different methods but I am unable to pinpoint the exact cause of the issue.
I've been able to put together a structure with Express that retrieves data from my database when the server stands up, but when I attach a route to the same method, I get "the" StackOverflow (I'm unsure if there is a single cause for the crash or if I'm dealing with two separate issues that both manifest as Stack Overflows)
I'll focus this question on one of the stack overflows in the hope that it is responsible for all of the crashes.
At any rate, this is the server config that was able to marshal data back to node from the .NET class library(which in turn makes the ADO.NET calls into my MSSQL db):
var express = require('express');
var http = require('http');
var edge = require('edge');
var app = express();
app.set('port',process.env.PORT || 3000);
app.use(app.router);
var repository = {
list: edge.func({assemblyFile:'bin\\Data.dll',typeName:'Data.GetListTask',methodName:'Invoke'})
});
app.get('/tickets', repository.list);
http.createServer(app).listen(app.get('port'),function(request,response){
console.log('Express server listening on port ' + app.get('port'));
console.log('[Before][repository.list]');
repository.list({}, function(error, result) {
console.log('[Result][repository.list]');
if(result){
result.forEach(function(item){
console.log('[List contains]{' + item.Id + '|' + item.Description + '}');
});
}
else{
console.log('No items found');
}
});
});
Whenever the server starts, the repository's list is retrieved and spooled to the console; however, if I use my /tickets route, the server crashes with a Stack Overflow.
The "good" response:
The crash when I try to activate my route (the real route is named 'tickets')
I'm not very experienced with node or express, so I'm not entirely sure I've specified that '/tickets' route properly.
This was a stupid problem with my Express route.
app.get('/tickets', function (request, response) {
ticketRepository.getTickets({}, function (error, result){
response.json(result);
});
});
returns the results from my database as expected.
protip: If you're trying to respond with "stuff", it helps to actually put "stuff" on the response.

How to do live update on section of page?

I need to refresh sections of my page to update when there is new data! what do i do? use jquery?
examples:
Yes, jQuery's great for this. Look into these methods:
http://api.jquery.com/category/ajax/
jQuery is usually not needed for basic AJAX. A simple example could be as follows:
liveSection = document.getElementById('latest-news');
request = new XMLHttpRequest;
request.open('GET', '/news-ajax', true);
request.send(null);
request.addEventListener('readystatechange', function() {
if (request.readyState == 4 && request.status == 200)
liveSection.innerHTML = request.responseText;
}, false);
If you're using Asp.NET, why not use an UpdatePanel? It's simple and reliable.
Edit
I just re-read your question and it looks (based on how you worded it) that you want to update a user's web page when the data changes on the server. I just want to make sure you understand that in a web app, the server can't trigger the browser to do anything. The server can only respond to browser requests, so you'll need to have the browser poll the server periodically.
I've created a simple example (using jQuery) to help you understand the breakdown of the things that will need to happen, which are:
1 - Periodically polling the server (via ajax) using Javascript's setTimeout to check that what is loaded into the browser is the latest content. We can achieve this by fetching the latest item ID or whatever and comparing it to a variable, which was initialised when the page first loaded.
2 - If the item ID does not match (a bit of an oversimplification) then we can assume that there has been an update, so we replace the content of some element with some content from some page.
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
function getLatestStuff() {
// fetch the output from a context which gives us the latest id
$.get("isthereanupdate.aspx", function(response) {
// we have the response, now compare to the stored value
if(resp != lastItemId) {
// it's different, so update the variable and grab the latest content
lastItemId = response;
$("#latestStuffDiv").load("updates.aspx");
}
});
}
$(document).ready(function() {
// the value which initializes this comes from the server
var lastItemId = 7;
setTimeout(getLatestStuff, 10000);
});
</script>
If you want to update when there is new data, you should look into comet or pubsubhubbub. jQuery can help you display the data in a pretty way, but you'll need to write stuff on the serverside to send the data.

Categories

Resources