res.send token and then redirect - javascript

I have an express app that upon calling a get request immediately returns a string token, then runs a python code. The python code after some time creates a json file that I need to send in another post request.
This python code may be called by different users that's why i need to assign them a token a soon as the app is called.
In the post request i'll also be modifying the json file and then sending it back
I'm trying to do res.send the token and then res.redirect to the post request, but i know it's impossible. Is there any other way i could send the token or redirect to the post request?
app.get('/', (req, res) =>{
res.send(token())
runPython((code)=>{
*takes around 10 sec*
res.redirect('/post')}}
app.post('/post', (req, res)=>{
*do stuff to file*
res.sendFile()

You cannot send multiple responses back to the client separated in time. You get ONE http response. So, once you've done res.send(token()), then that http request is done. You can't send any more data as part of that http request.
As you describe things, here are some of your options:
Combine both into one response. Wait to send the token until you have the python response too and then send them both in one JSON response. You won't be able to do a res.redirect() if you're also sending data back. So, you could send the redirect location back in the JSON and have the client manually do the redirect (by just setting window.location to a new URL). Presumably, there is client-side Javascript on the receiving end of this anyway since some form of code has to receive the token anyway to do something useful with it.
Use websocket/socket.io connection for subsequent server-initiated communication. Have the client connect a webSocket or socket.io connection. You can then response with the token and then later when the python has finished, you can send additional data over the websocket or socket.io connection. This will require additional code to be able to associate a particular websocket/socket.io connection with the client that made this request so you can tell which websocket/socket.io connection for this request to send a notification over.
Client-side polling for completion of python operation. Have the server send back the token and also send it some sort of request ID and then the client can poll the server every few seconds to ask the server if that python operation for that request ID is now done. When it gets a response from the server that the python is now done, then the client can manually redirect itself to /post to fetch the final data.

Related

How to deliver the result of asynchronous request from back to front (Callback)

Client send a request to my my service "A" then I send a request from service "A" to Camunda like "doSmthAndGet" then camunda replies "request accepted" and asynchronously calls another service "B" to process my request. After service B returns the result, Camunda will call API of my service "A" to return me this response. In what ways can I deliver this result to a web page (JS) to display to the client? I thought about a websocket, but I'm not sure if this is a good idea, because for one client such a request is sent once and after that the websocket is no longer needed. But I need some kind of "channel" to call the front side (JS) when I get a processed result for a particular client in my service "A".
I think I understand your predicament now, instead of:
Client <--> Server A <--> Camunda <--> Server B --> Results from server B on client
You have something like:
Client <--> Server A <--> Camunda --> Result 'OK' from camunda on client
Camunda <--> Server B --> Results from server B on Camunda
Camunda <--> Server A --> Results from server B on Server A
(I now you refer to services but for the sake of this explanation I prefer to refer to the machines)
When Server X makes a requests to Server Y then Server X is technically a client as far a that request is concerned. The communciation between Camunda and your server can really only work this way because the client (server A) is also a server.
If you want to send data to a client you must either make a request from that client or first establish a two-way connection, e.g. a websocket like you suggested.
Solutions
You could declare a variable, and simply hold off responding to the initial request until "step 3" fills it with some value but I fear that this approach is prone to all kinds of errors and not sustainable.
You could still use something like this approach, but instead of holding off the initial request you rely on the client to "Check back in later". Something you could do automatically at regular intervals using JS.
The challenge with both scenarios is that you have to implement or at least account for some kind of user session logic to make sure you send the right data back to the right user. For that reason I think your own suggestion to use WebSockets is perhaps the most elegant.
I don't think it is a problem to only use the WebSocket once, and if you want you can close the connection after the whole process has been completed.

What’s the difference between res.send and app.post?

I’m new to express and HTTP. The express library has app.get, app.post and res.send. As I understand it, app.get uses/is used with GET and app.post POST. Does res.send call POST?
res.send() sends a response to an incoming http request that has come into your http server.
app.post() registers a request handler with Express for a specific URL in your http server and for POST requests so that when your Express server receives a POST request at that URL, it will call this request handler.
Here's an example of res.send():
// configure request handler for GET request to /
app.get("/", (req, res) => {
res.send("hi"); // send response to incoming http request
});
Here's an example of app.post():
// this middleware reads and parses the body for content-type
// of application/x-www-form-urlencoded
app.use(express.urlencoded({extended: true}));
// configure request handler for POST request to /login
app.post("/login", (req, res) => {
// in a real request handler, this would be some sort of username
// and password comparison in a database and using appropriate crypto
if (req.body.username === "John" && req.body.password === "foobar99") {
res.send("login successful");
} else {
res.status(401).send("Login failed");
}
});
The express library has res.get and res.send. As I understand it, res.get uses / is used with GET.
You are perhaps confused because there is no res.get. Perhaps you meant app.get()? If so, app.get() configures a request handler for an http GET request to a specific URL. So, app.get("/books", ...) might display a page of all available books.
Does res.send call POST?
No. res.send() sends a response to an http request.
Here are the steps you can think of.
An http client (such as a browser or any piece of code) creates an http request and sends that request to a server.
That request will have both an HTTP verb such as GET, POST, PATCH, etc... and it will have a URL such as /login or /books.
The web server that the request was sent to receives that request. In the case of a web server using the Express framework, the Express server looks through its list of already registered routes (these routes were previously registered with app.get(...), app.post(...), app.use(...), etc... These are essentially listeners for specific routes. If the Express server finds an already registered route that matches both the http request verb and the URL, then it calls that route handler and pass it three arguments (req, res, next).
When the request handler code gets called, it can examine the req object to see any data about the incoming request such as the exact URL, any http headers on the request and so on. It can use the res object for sending a response such as setting any http headers on the response, setting content-type, setting an http status code for the response, creating and sending the body of the response, etc... res.send() is one way to send the response. There are also others such as res.sendFile(), res.json(), res.sendStatus() and so on...
After one of these methods is called that sends the response, then the underlying engine sends that http response back to the client that sent the original http request and the HTTP request/response is considered complete.
Those are two different modules/objects..
The Express Router supports HTTP methods for the server to listens and respond to - .get(), .post(), .put().
One of the arguments passed through the chain of middleware and handlers is the Response, which has a .send() method to send its response back to the client. The Response object can also be enhanced to send JSON, etc.

Express return post info to be processed by another function

I have this code:
app.post('/pst', function(req, res) {
var data = req.body.convo;
res.render('waiting.ejs'); //ADDED THIS
myFunc(data).then(result => {
res.render('success.ejs'); //THEN THIS
//---------------------------------
//clever way to send text file to client from the memory of the server
var fileContents = Buffer.from(result, 'ascii');
var readStream = new stream.PassThrough();
readStream.end(fileContents);
res.set('Content-disposition', 'attachment; filename=' + fileName);
res.set('Content-Type', 'text/plain');
readStream.pipe(res);
//--------------------------------------
}).catch( .....
What i want to do is when there is a POST,
1. grab the post information
2. do a res.render()
3. run a function with the post information as its parameters
4. do this code snippet that will allow the client to download stuff from the memory as a .txt file
5. do another res.render()
Everything works if we exclude the two res.render(). After i do one, i cannot set the headers. I get this error.
Error: Can't set headers after they are sent.
So i thought of a potential solution.
Is it possible that the app.post() will get the post data and do a res.render().
Then, return the post data, so another part of the code will handle calling the function with this data as parameter and then do the header manipulation thing, then finally do the last res.render().
Keep in mind this is the routes.js file.
HTTP is a request/response protocol. A client makes a request and gets one and only one response back. So, you can never call res.render() twice on the same request.
Your problem is really defined by this desired sequence:
Client sends request
Server starts to process request
Client shows progress
Server finishes processing request
Client shows final result
There are a number of ways to accomplish that:
Client uses Ajax instead of form post to send request
Client submits form via Ajax instead of form post
Client puts up progress on the page using DOM manipulation (changing of the current page contents, usually showing a visual overlay of some type)
Server works on request, not returning anything yet
Server finishes request and returns response to client with one res.render()
Client either inserts the returned content into the current page or issues a window.location = xxxx to change the current page to show new URL containing new contents.
Form post response that uses webSocket/socket.io to get final results
Client submits form
Server returns immediately response page that shows progress/waiting UI and that page also connects a webSocket or socket.io connection to the server
Server works on request
Server accepts webSocket or socket.io connection
Server finishes request and sends some type of result over webSocket/socket.io connection to the correct client
Client receives response over webSocket/socket.io and either updates the contents of the current page or changes page to a new URL
All done via webSocket/socket.io
Client loads original page
Client establishes webSocket/socket.io connection to server
Client sends form data to server over webSocket/socket.io connection
Client puts up progress/waiting overlay
Server starts processing request
Server finishes processing request
Server sends response from request back to client over webSocket/socket.io connection for that client.
Client receives response over webSocket/socket.io connection and either updates the contents of the current page or changes page to a new URL

Node.js/Express - how to access session data through method(using sockets)?

I've stored some Oauth data in session, and now I'd like to access it again, so I created a local API endpoint to feed that access token. It appears that if I make that request via a method though, it doesn't contain the request body, so it can't actually get the req.session.access_token.
Visiting this endpoint provides the right data if typed into the address bar, but the response is undefined when requested through a method. The method is being called through a socket, if that helps inform the advice.
//This is the endpoint
app.get('/instagram/accesstoken', function(req,res){
console.log("/instagram/accesstoken: ", req.session.access_token, ", req: ", req);
res.json({access_token: req.session.access_token});
});
//This is the method calling the endpoint
function getAccessToken(callback){
request({url: 'http://localhost:3000/instagram/accesstoken', method: "GET"}, function(err, resp, data){
console.log("getAccessToken: ", data);
if(err) { return callback(err); }
callback(null, data);
});
//Sockets
io.listen(server);
io.on('connection', function(socket){
...
getAccessToken(function(err, token){...}
...
});
I'm open to alternative solutions as well. How can I feasibly get access to the session data? Thanks for your patience, and for taking a look.
Used express and socket.io for just a few days but here's a bit thought:
1. You're having problem getting req.session, which is picked up by the server from its session storage. The server does this with the help of sessionid(usually named sessionid or sid) stored in the browser cookie, which is sent in the headers of every request. So you should probably check the request headers(on the requests made after the socket connection) to see if the cookie is correctly sent and whether it is including the sessionid we want.
2. You're telling the client to request the accesstoken on your site when the socket connects so the server can get the Oauth access_token to request or send infomation to other apps(if I understand correctly). This is a bit of an overhead(one too many request) since you may just get the session id from socket request's header and then get this user's session data with it. However this may need a little tweak since the framework's session functionality can't check the session id from the req object automatically. This can be a bit difficult if the session functionality doesn't provide relevant functions so you'll have to dive in the framework. But it's an alternate if plan 1 doesn't work out(and is also more elegant since it saves one request :) (but may be harder as well :( ))
To access session data via sockets you need to use a plugin like https://www.npmjs.com/package/express-socket.io-session
With this you can access session data via socket calls.

Making post request from redirection in node.js

I am trying to redirect to another URL from node js by using response.writeHead method
response.writeHead(301, {Location : <redirecturl>})
I need to have this redirection is being executed by POST method, however it is always executed by GET. What is the way that the redirection can be made as a POST request.
A redirect by default sends a GET request. According to the HTTP spec, a 301 redirection means sending a GET request. If you want to redirect with the same method (POST), you can try doing a 307 redirect instead.
There is no difference between redirection in both GET and POST methods. Both method should work find. Better you can your expressjs framework in which it is
res.redirect('http://example.com');
Be careful, when using status code 301 which means Moved Perman­ently. Once browser gets 301 status code, it will directly try the redirected URL from the next time.
Without seeing more of your code, I believe this is what you are describing:
The client has made a request to your application using an HTTP method (get, post, etc.) You are responding to that request by sending back a 301 error and a new URL (redirecturl)
The client then decides to implement a get request for the redirecturl.
You can't change how a client responds to a 301. That is out of your control and it is normal for browsers to initiate a get for the redirecturl.
You could initiate a post request from your server to the redirecturl.
You could send back a webpage which would then submit a post request from the client.
What are you trying to achieve?

Categories

Resources