What i want to do is to read the property name of the request i send to my express.js server.Here is how i pass the json data to a post request.
document.querySelector('#checkout').onsubmit= async e =>{
const form = new FormData(document.querySelector('#checkout'))
let user = createUserInfo(form),
order = {
name: "Test_Name"
}
fetch("/checkout/create-order", {
method: "POST",
mode: "same-origin",
redirect: 'manual',
headers:{
"Content-Type": "application/json"
},
body: JSON.stringify(
{
order: order,
user: {
name:"test_Name"
}
}
)
}).then(res=>{
res.ok
}).then(data=>{
console.log(data)
})
}
And this is how i read it using express.js:
app.use(express.json());
app.use(bodyparser.json());
app.use(bodyparser.urlencoded({ extended: false }));
const YOUR_DOMAIN = 'http://localhost:4242/checkout.html';
app.post('/checkout/create-order', async (req, res) => {
console.log(req.body.order.name)
}
When i try to read the name property i get an error.
C:\xampp\htdocs\server.js:9
console.log(req.body.order.name)
^
TypeError: Cannot read properties of undefined (reading 'name')
Add e.preventDefault() to the beginning of the onsubmit handler.
By default, when the user clicks a form submit button, the browser will send a URL encoded POST request to the URL defined in the form's action attribute (or if there is no action, the current page).
<form action="/somewhere_else"></form>
Your express code is seeing the request sent from the browser, which doesn't have any of the values you defined in the fetch request.
This also causes the page to reload and interrupt your fetch request code before its sent. By adding event.preventDefault() you suppress this behavior and your code should run as expected.
P.S.
You don't need to use both express.json() and bodyparser.json(). Body-parser is included with Express, so both of those middlewares are doing the same thing. You can also use express.urlencoded() instead of bodyparser.urlencoded().
Your server-side code is correct in my opinion, but a small tip, you don't need to use bodyparser.json() and express.json() both do the same thing.
just chose one and stick to it.
Related
Here is my nodejs code that works perfectly with https site.
app.use(cors({ origin: '*' }));
app.use(express.json())
app.use("/user", userRouter);
app.use("/mention", mentionRouter);
app.use("/request", requestRouter);
But the problem is if I send the request from any HTTP site, I get an error saying TypeError: Failed to fetch and get no response. Here is my frontend code.
const response = await fetch(WEB_URL + "mention", {
method: "POST",
body: JSON.stringify({
to: users,
text,
link: window.location.toString(),
}),
headers: {
"x-access-token": accessToken,
"Content-Type": "application/json",
},
});
I tried answers from this Getting "TypeError: failed to fetch" when the request hasn't actually failed but not working.
Sorry to be one of those people, but your variables are not defined in your snippet so I can't really see what you have defined. Example:
const response = await fetch(WEB_URL + "mention",
Nobody knows what WEB_URL means and it can be apart of the problem.
Also, window.location can be used like http://example.com/, but it is an object so it could print "[object Object]". Instead, try using window.location.href. Your problem most likely is that the Fetch JS API is not available with HTTP sites for security reasons. There's not much more to the problem.
Using request you can forward a POST multipart/form-data request from express to another server without modifying the body/parameters of the initial request and then return the response from the other server to express. With axios this feature appears to be missing.
CODE:
header
const request = require('request');
const axios = require('axios');
const express = require('express');
const app = express();
app.listen(3000);
const FORWARD_URL = 'https://example.com/'
Working example using request
app.post('/test/0', (req, res) => {
req.pipe(request(FORWARD_URL)).pipe(res);
})
Attempt #1
app.post('/test/1', (req, res) => {
req.pipe(axios.post(FORWARD_URL)).pipe(res);
})
// internal/streams/readable.js:827
// dests[i].emit('unpipe', this, { hasUnpiped: false });
// ^
// TypeError: dests[i].emit is not a function
// at IncomingMessage.Readable.unpipe (internal/streams/readable.js:827:16)
// at unpipe (S:\_Work\[REDACTED]\node_modules\unpipe\index.js:47:12)
// at send (S:\_Work\[REDACTED]\node_modules\finalhandler\index.js:306:3)
// at Immediate.<anonymous> (S:\_Work\[REDACTED]\node_modules\finalhandler\index.js:133:5)
// at Immediate.<anonymous> (S:\_Work\[REDACTED]\node_modules\express\lib\router\index.js:635:15)
// at processImmediate (internal/timers.js:466:21)
Attempt #2
app.post('/test/2', (req, res) => {
req.pipe(axios({
url: FORWARD_URL,
method: 'POST',
responseType: 'stream'
})).pipe(res);
})
// SAME ERROR AS ABOVE
Attempt #3
app.post('/test/3', async (req, res) => {
const axiosRequest = await axios({
url: FORWARD_URL,
method: 'POST',
responseType: 'stream',
data: req
})
axiosRequest.data.pipe(res);
})
// server at FORWARD_URL receives improperly formatted request body, changing request content-type headers has no affect
// ------WebKitFormBoundaryc4BjPwpdR4mG7CFN
// Content-Disposition: form-data; name="field_name"
//
// field_value
// ------WebKitFormBoundaryc4BjPwpdR4mG7CFN--
A similar issue has been addressed here, the accepted answer, while not very clear, does answer the question, however, only covers GET & POST application/x-www-form-urlencoded requests, This is regarding POST multipart/form-data requests.
Ideally I'm looking for a solution that functions identically to the request example using axios, this works great for my use case as it includes file uploads, because of this, I want to avoid parsing the body and instead just forwarding it onto the next server.
Testing of the above routes was performed with postman
Changing the Axios request headers to the equivalent ones obtained from the original request, resolved the error for me.
Code:
const axiosRequest = await axios({
url: FORWARD_URL,
method: 'POST',
responseType: 'stream',
data: req
})
I have just copied the original request headers to the new request
const axiosRequest = await axios({
url: FORWARD_URL,
method: 'POST',
responseType: 'stream',
data: req,
headers: {
...req.headers
}
})
The following code worked for me for POSTing streams with content type multipart/form-data:
app.post('/test/0', async (req, res) => {
const response = await axios.post(FORWARD_URL, req, {
headers: {
'content-type': req.headers['content-type'],
},
});
return res.send(response.data);
})
In my case I did not need to set the responseType header to stream. This might depend on the response you are getting from the API.
What is important is:
posting the entire request object (not just the body!)
setting the content-type header of the outgoing request to the same value as the incoming request
Passing just the body of the incoming request to the outgoing request will result in the API (the reader of the stream) endpoint receiving an empty object (which it will initialise with default values).
Passing the body of the incoming request and setting the content-type header will result in the API endpoint receiving a null body.
I got following format when i send post request from postman.
{
ID:"66",
Blod:"test",
Allergic:"no",
Chronic:"no"
}
But i got this format when i send post request using react app post method.
[Object: null prototype]
{
'{
"ID":"123456789",
"Blod":"22334445",
"Allergic":"6677788",
"Chronic":"3445566"}': ''
}
please help me how can I got the same format of postman to insert data correctly.
this is my method from react app uisng axios module :
submithandler=(e)=>{
e.preventDefault();
axios.post('http://localhost:8000/api/addsickers',
JSON.stringify({
ID:'123456789',
Blod:'22334445',
Allergic:'6677788',
Chronic:'3445566'
}),
)
.then(response=>{
alert(response);
})
.catch(err=>{
alert("catch"+err);
});
}
I use parsing on api
app.use(bodyparser.json());
// parse application/x-www-form-urlencoded
bodyparser.urlencoded({ extended: false });
// parse the raw data
app.use(bodyparser.raw());
// parse text
app.use(bodyparser.text());
Please check the postman request configuration
settings as follows.
If the problem you are facing now is that how to process incoming react request, the
following code snippet will helps you.
router.post('/', (req, res) => {
let request = JSON.parse(JSON.stringify(req.body));
console.log(request.ID);
});
you don't need to use 'JSON.stringify' , like this:
submithandler=(e)=>{
e.preventDefault();
axios.post('http://localhost:8000/api/addsickers',
{
ID:'123456789',
Blod:'22334445',
Allergic:'6677788',
Chronic:'3445566'
},
)
.then(response=>{
alert(response);
})
.catch(err=>{
alert("catch"+err);
});
}
In your code you don't need this code:
// parse the raw data
app.use(bodyparser.raw());
// parse text
app.use(bodyparser.text());
As the documentation states:
bodyparser.raw() Returns middleware that parses all bodies as a Buffer and only looks at requests where the Content-Type header matches the type option.
And
bodyParser.text() Returns middleware that parses all bodies as a string and only looks at requests where the Content-Type header matches the type option. This parser supports automatic inflation of gzip and deflate encodings.
You have to change that line from:
bodyparser.urlencoded({ extended: false });
to:
app.use(bodyparser.urlencoded({ extended: false });
I have solved this by using fetch method like the following :
senddata(event){
event.preventDefault();
//if(!this.formvalidation())
//{
try{
fetch('https://localhost:8000/api/addsickers/',{
method:'post',
mode:'no-cors',
headers:{
'Accept':'application/json',
'Content-type': 'application/json'
},
body:JSON.stringify({
ID:this.state.code,
Blod:this.state.blod,
Allergic:this.state.allergic+" - "+this.state.allergicdescription,
Chronic:this.state.chronic+" - "+this.state.chronic_description
})
});
alert("data goes")
}catch(e){
alert(e)
}
//}
}
and in api I did :
let request = JSON.parse(req.body)
console.log(request);
and I got the same forma of postman tool that let me to call attributes correctly for insert , for example : request.ID return the correct value.
thank you all for your help.
After passport authenticating success i want to pass the req.user data to the component
using res.sendFile().
I found this answer Here
But i don't know how to read the options param on the component in componentDidMount()
Can any one help me ?
There is no standard way to send mixed JSON + file content by using just the sendFile() method. As a workaround, you can send your JSON data as a custom response header:
const options = {
headers: {
'Access-Control-Expose-Headers': 'User',
'User': JSON.stringify(req.user),
}
};
res.sendFile(path.join(__dirname, '../assets', 'index.html'), options);
Note that the Access-Control-Expose-Headers header is required, in order for your client to always be able to access the extra header.
Then, assuming you are using axios on the frontend:
axios.get(YOUR_URL, response => {
const user = JSON.parse(response.headers['User']);
console.log('User Object', user);
});
With fetch:
response.headers.get('User');
How to create a post service with formdata?
I sent formdata by Axios.
However, the value of 'req.body.title' on the node-express server is empty.
So now I am sending fetch in the following format.
But I need to upload the file to the server, so I want to send it using formData.
let bodys = 'title=a1&contents=b'
fetch("http://localhost:5000/test", {
method : 'post',
headers : {
'Content-type' : 'application/x-www-form-urlencoded; charset=UTF-8'
},
body: bodys
})
.then(function(response){
console.log('Request Succeded ', response);
})
.catch(function (error){
console.log('Failed ', error)
})
I wrote new data using append with new FormData(),
I checked that FormData contains a value on React.
However, the node-express server did not enter the body.
please let me know what to do...
Try sending FormData object instead of raw string as your request body.
const bodys = new FormData();
bodys.append('title', 'a1');
bodys.append('contents', 'b');
This form data will be available in request.body in express.js server.
Edit: to parse the FormData in express.js, you need a middleware like multer
const upload = require('multer');
app.use('/', upload.any(), yourRouteHandler);
You are sending just a string so
You can access your body like below
let bodys = 'title=a1&contents=b'
console.log(req.body); //will print title and contents as you are sending
If you want to access title and contents separately then you have to send data as an object
const bodys = {“title”: “a1”, “contents”: “b”}
console.log(“title”, req.body.title); //will print a1
console.log(“contents”, req.body.contents); //will print b
Chec this thread for more details https://github.com/github/fetch/issues/263