im trying to make my own api and one part of it is that I want it to be able to receive text and files from a discord webhook, the text part works fine but when I send the file I can't seem to figure out how to receive it. I looked around for a bit and saw that req.files will return the file but I just get undefined. Here is my api code:
const express = require('express'),
bodyParser = require('body-parser'),
base32 = require('base32'),
const pass = "5'g5?cDzy}\\p5zAwvT[DJ/SeD"
const port = 8080
function denied(res) {
res.status(403);
res.send('no');
}
const api = express();
api.use(bodyParser.json());
api.listen(port, () => { console.log(`api running on port ${port}`) });
api.post('/webhook', (req, res) => {
if (!req.headers) {
denied(res);
}
var auth = req.headers['authorization'];
if (auth && base32.decode(auth) === pass) {
console.log(req.files) //undefined
res.send('done');
} else {
denied(res);
}
});
and this is the code I use to send the file and text:
import requests
key = '6mkped9zcd27mybxbhr3ayj1exv58pu498qn6ta4'
header = {
"Content-Type": "application/json",
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11",
'Authorization': key
}
info = {
"avatar_url":"https://cdn.discordapp.com/attachments/901070985434918965/904813984753000469/nedladdning_14.jpg",
"name":"test",
"embeds": [...]
}
r = requests.post('http://localhost:8080/webhook', headers=header, json=info)
r2 = requests.post('http://localhost:8080/webhook', headers={'Authorization': key}, files={'file': open('test.zip','rb')})
print(r.text, r.status_code)
print(r2.text, r2.status_code)
Upload files (e.g. how requests does it) are sent as multipart/form-data payloads.
As per body-parser's npm page,
[...] does not handle multipart bodies, due to their complex and typically large nature. For multipart bodies, you may be interested in the following modules...
You'll need one of those modules, and you'll then need to read its documentation to see if it provides eg. the req.files you've seen somewhere. Otherwise it will indeed be undefined.
Related
I am adding a server extension to an existing same-server backend:
import server from 'myserver';
import { verifyJwt } from 'jwt.middleware';
import axios from 'axios';
const app = server.getApp();
app.use(function (ctx, next) {
ctx.cacheControl = {
noCache: true
};
return next();
});
const client = axios.create({
headers: {
'Cache-Control': 'no-cache',
Pragma: 'no-cache',
Expires: '0'
}
});
const router = server
.getRouter({ prefix: '/myuserendpoint' })
.use(verifyJwt);
router.get('/goodusers', async ctx => {
const result = axios.get('/api/users');
// do something with result
ctx.body= result;
});
I run the server and try to access http://localhost:4000/myuserendpoint/goodusers which is going through,but when I expect axios to call http://localhost:4000/api/users (a working endpoint), it gives me 404 error and in the error message I find a call to a wrong address of http://localhost/api/users instead (where is the port number?).
I need to extend the functionality of an existing same-server endpoint to do some changes in the result and send it back via a new route. We have /users endpoint and I want to have /goodusers which uses the existing /users API and filter some of them with a logic.
What am I missing?
I am trying to upload image to my api. Uploading with postman works fine. When I previously used expo go all worked fine as well. Once I switched to react native native code I get following error.
I am sure my endpoint is correct and it is HTTPS. Other post request that are not multipart/form data/PUT requests or Get requests work perfectly. Here is code:
const openImagePickerAsync = async () => {
let permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (permissionResult.granted === false) {
alert("Permission to access camera roll is required!");
return;
}
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
quality: 1,
});
console.log(result)
const { cancelled } = result as ImageInfo
if(cancelled == false)
{
const { uri } = result as ImageInfo
const bodyy = new FormData();
const bod = JSON.parse(JSON.stringify({ uri: uri, type: 'image/jpeg', name: 'profilePicture'+userId+".jpg" }));
bodyy.append('demo_image', bod);
try{
const log = await fetch("https://endpoint/api/upload/picture/" + userId, {
method:'POST',
body: bodyy,
headers: {
'Content-Type': 'multipart/form-data',
Accept: "application/json",
}
})
console.log(log)
Alert.alert("Profile picture uploaded!")
}
catch (error){
console.log(error)
}
}
else{
Alert.alert("You did not choose picture to upload.")
}
}
And here is response:
Edit1: I have also tried running my server on localhost with http and writing IPv4 address of my PC I am running server on (besides localhost:8000) I wrote ip:8000. Did not help..
your problem is about CORS (Cross-Origin Resource Sharing)
you must be add this command in your server
npm install express cors
const express = require('express')
const cors = require('cors')
const app = express()
app.use(cors())
and cors() allowed the client to access this route
but if you didnt use express you can solve this problem with cors header request
headers: {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'multipart/form-data',
}```
Variations of my issue have been asked dozens of times, but nothing I’ve tried worked.
My Node.js API works as expected on localhost for GET and POST requests.
On my EC2/nginx instance, the server block was correctly configured and served a static index over https.
Then I configured this server block as a proxy to my API port (8000) and it also returns that the API is listening.
Then I ran a simple GET /index endpoint that is routed and works correctly.
However, a similar POST /checkEmail endpoint (which, remember, works on localhost) here times out with a 504 error. This is where it gets weird.
It won’t even console.log the payload, the first line of the function. That means it isn’t even routed correctly. Here are my routes:
const API = require("./controllers/api");
module.exports = [
{ method: 'POST', path: '/checkEmail', options: API.checkEmail },
{ method: 'POST', path: '/sendEmail', options: API.sendEmail },
{ method: 'POST', path: '/recaptcha', options: API.recaptcha },
{ method: 'GET', path: '/index', options: API.index }
]
Since that the GET request returns the expected response, then it means all of these are true:
The firewall rules are letting traffic through the 443 (HTTPS) port
That traffic is proxied through the 8000 (API) port
The server block is serving the files correctly
The ssl certificate works
The request is sent to the upstream server
The endpoints:
const axios = require("axios");
const env = require("dotenv").config();
const AWS = require("aws-sdk");
const subscriber = require("./middleware/subscriber");
const sanitizer = require("./middleware/sanitizer");
exports.index = {
cors: {
origin: ["*"]
},
handler: (request, h) => {
return "API Fluente";
}
}
exports.checkEmail = {
cors: {
origin: ["*"]
},
handler: async (request, h) => {
// This is never logged:
console.log(request.payload);
const payload = request.payload;
const email = await sanitizer.email(payload.email);
if(!email) throw new Error("Invalid email");
const response = await verifyEmail(email);
console.log("checkEmail attempt:", email, response.data)
if (response.status === 200) {
return h.response(response.data).code(200);
}
}
}
What I’ve tried:
Minimal/Full server block conf settings
curl the POST request from the EC2 CLI
Change ports from 8000 to something else (eg 8003)
Increasing timeout duration doesn’t make sense because these are simple requests that should return a response in a very short time.
None of these made any difference.
Found the problem! As it turns out, it had nothing to do with AWS services or Node.
I was using the deprecated hapi package, when I should have been using #hapi/hapi.
Ok, so i need to proxy file array upload from my express node app, to remote PHP Api.
Ideally i would use something close to Nginx proxy since it has same modules with node.
If not,i would emulate form resend.
Can you help find the best way for doing this?
So, i did not found execaly how to proxy request itself, as it would do nginx, but at least i figured out how to redirect request with all it's data to different source.
So, here we use express-fileupload to get our file data from req, and form-data to create a form and send data.
import app from '#app';
import { authMw as checkJwtAndAddToRequest } from '#middleware/Auth';
import { Router } from 'express';
import fileupload, { UploadedFile } from "express-fileupload";
import FormData from 'form-data';
//add this MW to add files to you'r req
app.use(checkJwtAndAddToRequest)
app.use(fileupload());
app.post('/upload', (req, res) => {
const uploadableFiles: UploadedFile[] | UploadedFile | undefined = req.files?.formFieldName;
if(!uploadableFiles) {
throw Error('Pls add files to upload them');
}
//Transorm single file to same form as an array of files
const files: UploadedFile[] = Array.isArray(uploadableFiles) ? uploadableFiles : Array<UploadedFile>(uploadableFiles);
//create form
const form = new FormData();
//add files
files.forEach(
file => form.append('files[]', file.data.toString(), file.name)
)
//Submit
form.submit({
protocol: 'http:',
host: process.env.API_URL,
path: '/api-path-for/file/upload',
method: 'POST',
headers: {
//Add auth token if needed
authorization: `Bearer ${String(req.body.jwtToken)}`
}
}, (err, response) => {
if(err) {
//handle error
res.status(503).send('File server is currently unavailable');
}
//return remote response to original client
response.pipe(res)
});
});
I am struggling with a simple media (mp3/mp4) upload to a server using axios.
I have an angular application that creates a formData and send this formData to node server via :
return this.http.post(this.apiURL + '/uploadFile', formData);
My server method looks like this :
app.post('/api/uploadFile', upload.single('file'), (req, res) => {
inputFile = req.file;
let fd = new FormData();
fd.append('file',inputFile.buffer, inputFile.originalname);
axios.post(uploadFileURL , fd, { headers: { 'Content-Type': 'multipart/form-data' } })
.then((response) => {
console.log(response);
})
.catch((error) => {
console.error(error)
})
})
The inputFile contains the original files. The error I get now is that the request is not a multipart request...
I tried as well to define the formData differently :
formData = {
file: {
value: inputFile.buffer,
options: {
filename: inputFile.originalname,
contentType: inputFile.mimetype
}
}
};
Which brought me to a different error : 'Failed to parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found'
Am I doing something wrong ?
I am wondering if this could be link to the fact that I use const bodyParser = require('body-parser'); for some of my other requests.
Any help would be appreciated!
Thanks
EDIT :
Here is my need and what I've done so far :
I have a web application that allow users to upload media files.
I have to send those files to a server, but I can not use the browser to send the request directly.
I created a nodejs application to realize the proxy task of getting the files from the browser and sending it to my remote server.