I am trying to make an app which should do the following:
step 1) user enters input into a textarea
step 2) that input is posted to the server
step 3) server is processing that input and generating an ouput
step 4) server generates a custom url (.../output/output_ID) where the output is shown and immediately redirects the user to that url
the issue is with step 4). I am using raw javascript for front-end and nodejs with express for backend.
client side:
fetch('/postInput', {
method : 'POST',
body : JSON.stringify({input : inputBox.value.toString()}),
headers: new Headers({ "Content-Type": "application/json" })
})
server side:
app.post('/postInput/', jsonParser, (req, res) => {
let inputText = req.body;
let output = processInput(inputText);
let outputID = generateOutputId();
// now the user should be redirected to the following link:
// /output/outputID
// the new url should show the output
});
There are two possible solutions, depending on your "architecture":
If you are posting the data using a good old submit button, then you could send a response with the 302 status and a Location header that contains the required URL
If you are posting the data using Javascript with an XMLHttpRequest, then you'll have to redirect with this Javascript line: location = 'your URL'
Related
I have an app which uses Flask as a server, I use JavaScript in front-end and Python in back-end (flask). I have a problem with sending data using REST API from flask into JS.
The issue is that the users are receiving another users data. Here's hypothetical situation:
user A starts a new browser session and when he clicks he receives users A data (everything is OK at this point),
user B starts a new browser session and when he clicks he receives users B data (everything is OK at this point as well),
user A refreshes a browser and when he clicks he receives users B data and that is the problem
As you can see everything is working correctly but only if the user starts a new browser session. When the user refreshes the browser it all goes wrong.
The app has a few hundred lines of code so let me show you the most important part of the code.
Here is my simplified JS code:
document.getElementById('geolocate').addEventListener('click', event => {
const option ={
method: 'GET',
headers: {
'content-type': 'text/plain',
'cache-control': 'no-cache',
'cache': "no-store"
}
}
fetch('myUrl/api/v1/myEndpoint', option)
.then((response) => {
return response.text();
});
});
As you can see, it is just a simple event with fetch which is a receiver of POSTed data from backend.
Here you can see Flask code:
#app.route('myUrl/api/v1/myEndpoint', methods=['GET', 'POST', 'OPTIONS'])
def db_cords():
with open('/var/www/html/test.txt', 'r') as our_file:
for line in our_file:
return line
It reads the first line of our /var/www/html/test.txt file and sends it to the endpoint.
Here you can see the configuration of Flask:
app = Flask(__name__)
app.debug = False
app._static_folder = os.path.abspath("templates/static/")
config = {
"DEBUG": True, # some Flask specific configs
"CACHE_TYPE": "SimpleCache", # Flask-Caching related configs
"CACHE_DEFAULT_TIMEOUT": 10
}
# tell Flask to use the above defined config
app.config.from_mapping(config)
if __name__ == '__main__':
log = logging.getLogger('werkzeug')
log.disabled = True
app.run(host, port, debug, ssl_context=context)
I tried to add no-cache and simple-cache flags in headers but it did not help. Also I tried to use a decorator #after_request.
Everything in the app is working just fine. The only problem I have is the browsing session. Do you guys have any idea how to solve my issue?
I am trying to get this working now for days -.-
Using a simple NodeJS express server, I want to upload an image to a Django instance through Post request, but I just can't figure out, how to prepare the request and embed the file.
Later I would like to post the image, created from a canvas on the client side,
but for testing I was trying to just upload an existing image from the nodeJS server.
app.post('/images', function(req, res) {
const filename = "Download.png"; // existing local file on server
// using formData to create a multipart/form-data content-type
let formData = new FormData();
let buffer = fs.readFileSync(filename);
formData.append("data", buffer); // appending the file a buffer, alternatively could read as utf-8 string and append as text
formData.append('name', 'var name here'); // someone told me, I need to specify a name
const config = {
headers: { 'content-type': 'multipart/form-data' }
}
axios.post("http://django:8000/images/", formData, config)
.then(response => {
console.log("success!"); // never happens :(
})
.catch(error => {
console.log(error.response.data); // no file was submitted
});
});
What am I doing wrong or did I just miss something?
EDIT
I just found a nice snippet with a slighlty other approach on the npm form-data page, on the very bottom (npmjs.com/package/form-data):
const filename = "Download.png"; // existing local file on server
let formData = new FormData();
let stream = fs.createReadStream(filename);
formData.append('data', stream)
let formHeaders = formData.getHeaders()
axios.post('http://django:8000/images/', formData, {
headers: {
...formHeaders,
},
})
.then(response => {
console.log("success!"); // never happens :(
})
.catch(error => {
console.log(error.response.data); // no file was submitted
});
sadly, this doesn't change anything :( I still receive only Bad Request: No file was submitted
I don't really have much Django code just a basic setup using the rest_framework with an image model:
class Image(models.Model):
data = models.ImageField(upload_to='images/')
def __str__(self):
return "Image Resource"
which are also registered in the admin.py,
a serializer:
from .models import Image
class ImageSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Image
fields = ('id', 'data')
using automatic URL routing.
I wrote a simple test script and put the same image on the django server, to verify that image uploads works, and it does:
import requests
url = "http://127.0.0.1:8000/images/"
file = {'data': open('Download.png', 'rb')}
response = requests.post(url, files=file)
print(response.status_code) # 201
I had a similar problem: I used the same Django endpoint to upload a file using axios 1) from the client side and 2) from the server side. From the client side it worked without any problem, but from the server side, the request body was always empty.
My solution was to use the following code:
const fileBuffer = await readFile(file.filepath)
const formData = new FormData()
formData.append('file', fileBuffer, file.originalFilename)
const response = await fetch(
urlJoin(BACKEND_URL),
{
method: 'POST',
body: formData,
headers: {
...formData.getHeaders(),
},
}
)
A few relevant references that I found useful:
This blog post, even though it seems the author manages to send form data from the server side using axios, I did not manage to reproduce it on my case.
This issue report in the axio repository, where one comment suggests to use fetch.
In your node.js express server instead of adding the image to the form data, try directly sending the stream in the API post.
const filename = "Download.png"; // existing local file on server
//let formData = new FormData();
let stream = fs.createReadStream(filename);
//formData.append('data', stream)
let formHeaders = formData.getHeaders()
axios.post('http://django:8000/images/', stream, {
headers: {
...formHeaders,
},
})
.then(response => {
console.log("success!"); // never happens :(
})
.catch(error => {
console.log(error.response.data); // no file was submitted
});
I still didn't manage to get this working with axios so I tried another package for sending files as post requests, namely unirest, which worked out of the box for me.
Also it is smaller, requires less code and does everything I needed:
const filename = "Download.png"; // existing local file on server
unirest
.post(url)
.attach('data', filename) // reads directly from local file
//.attach('data', fs.createReadStream(filename)) // creates a read stream
//.attach('data', fs.readFileSync(filename)) // 400 - The submitted data was not a file. Check the encoding type on the form. -> maybe check encoding?
.then(function (response) {
console.log(response.body) // 201
})
.catch((error) => console.log(error.response.data));
If I have some spare time in the future I may look into what was wrong with my axios implementation or someone does know a solution pls let me know :D
I am currently creating an application where I used MongoDB to store login data , nodejs for creating API and front end JS HTML to display the page. I am Creating user where i pass the email id and password via fetch ajax POST call to the backend node server. The backend api route creating the user in DB. I want after creating the user I want to redirect to a different page. How can i do that? her is my code snippet.
//front end fetch call
async function createUser(email , password) {
return fetch("http://localhost:3000/user",
{
// Adding method type
method: "POST",
// Adding body or contents to send
headers :{
"content-type": "application/json"
},
body: JSON.stringify({
"userId" : email.value,
"password" : password.value
})
});
}
//beckend code
app.post('/user', async (req, res) => {
// res.header("Access-Control-Allow-Origin", "*");
// res.header("Access-Control-Allow-Methods", "POST,OPTIONS");
const {error} = validate(req.body);
if (error) {
return res.status(400).send(error.details[0].message);
}
let user = await User.findOne({userId : req.body.userId});
if(user) return res.status(400).send("User already registered");
let newUser = new User (
{
userId : req.body.userId,
password : req.body.password
}
);
newUser = await newUser.save();
res.redirect('/logged');
//res.send(newUser)
//res.send("<h1>Hi</h1>");
//res.sendFile((path.join(__dirname+'/loggedon.html')));
//res.send("<h1>Hi</h1>");
}
);
app.get('/logged' , function(req, res){
res.send("<h1>Hi</h1>");
// res.setHeader(200 , 'Content-Type' , 'text/html');
// fs.readFile('./loggedon.html', function(err , data){
// res.write("<h1>Hi</h1>");
// })
});
I was checking sending only HI. but this will work fine in local server. but how will i send data to Front end. Please let me know. comment lines are the things I already tried.
res.redirect sends an HTTP redirect response which means "You asked for some data from this URL. You can get it from this URL instead".
Since you made the request with Ajax, the redirect will be followed, the new URL requested, and the result passed to the Ajax handler.
You haven't written a handler (or, if you have, you haven't bothered to include it in the question) so nothing happens.
Aside: It is important to note that it does not mean "Load the new URL in the main browser window".
The new URL will only be loaded in the main browser window if the request was intended to be loaded there in the first place.
Yours was not. It is an Ajax request.
You could have the Ajax handler assign a new value to location when the promise resolves.
Frankly, if you want to load a new page, I'd question the use of Ajax in the first place and just design the system to use a regular form submission with no client-side JS involved at all.
I have an app in ReactJs, using Axios and Papaparse.
I have a page where a user drop a csv file in a box, I automatically download the csv, update and make some change in the data, and send a new csv file to a server.
I did all until I arrive to the part where I need to create a new csv, and upload it to the server.
Here is my code currently :
const data = papaparse.unparse(destinationUpdateData, {
header: true,
skipEmptyLines: true
});
// data is a string in csv format
const file = new File([data as BlobPart], "destination.csv", { type: "text/csv" });
// I get a File type.
const paramsDestination = {
project_id: this.props.projectId,
datastore_id: 'DESTINATIONS',
file: file,
id: ["1", "2","3"]
}
// the data I would like to send is build
Axios.post(`new_item_file_attachment`, params, {headers: {"Content-Type": "multipart/form-data"}})
//I send to the server
The thing is, my server is expecting a request with a content Type of multipart/form-data, but I don't get how manually set my parameter to match this type.
The api call currently don't work, because the data is passed like a json, and the server reject it.
Is it possible to achieve it ?
I tried using FormData, but I can't see how to send boolean and array
Not 100% familiar with Axios but it should be something like this:
var params = new FormData();
params.append("project_id", this.props.projectId);
params.append("datastore_id", 'DESTINATIONS');
params.append("file", file);
params.append("id", JSON.stringify(["1", "2","3"])); // Arrays must be stringified
Axios.post(`new_item_file_attachment`, params)
You definitely need to put everything in FormData object. Last time I was doing this, I also had to remove the "Content-Type": "multipart/form-data" from the header. I believe the correct header should get filled in automatically. Try it with and without that stating a header and let me know if either works.
Here is my solution.
const data = new FormData();
data.append("project_id", id);
data.append("file", file);
axios.post(url, data);
Try and comments when some errors occur.
My goal is to fetch the status data from a UBNT radio (https://www.ubnt.com/) using an HTTP request. The web interface url is formatted as http://192.168.0.120/status.cgi. Making the request requires a authentication cookie. Using the cookie copied from the existing web interface I am able to successfully retrieve the data.
This is my current code using the Meteor framework.
radioHost = "http://192.168.0.120";
HTTP.call("POST", radioHost + "/login.cgi",
{
headers: {
"Content-Type": "multipart/form-data"
},
data: {
username: "ubnt",
password: "ubnt"
}
}, (err, res) = > {
if(err) return console.log(err);
var cookie = res.headers["set-cookie"][0];
HTTP.call("GET", radioHost + "/status.cgi", {
headers: {
cookie
}
}, (err, res) = > {
if(err) return console.log("Error");
console.log(res);
})
})
The above code achieves both request successfully. However the server is responding to the first with a faulty token ("set-cookie" string). Using the cookie from the existing web framework the response is correct.
Here is a library written in Python that I believe does a similar thing. https://github.com/zmousm/ubnt-nagios-plugins
I believe my problem lies within the HTTP request and the web api not cooperating with the username and password.
Thanks in advance for any help.
A direct POST request to a url is not a recommended way. When you open a browser you just don't directly login. You fetch the page and then submit/login
Not simulating this behavior may impact certain sites depending on how the server works.
So if always want to look at the simulating like a real user/browser would do, make a GET request first and then the POST.
Also capture any cookies from the first GET request and then pass the same on to the next one