Axios: POST-Anfrage funktioniert im Browser, aber nicht auf Node

Erstellt am 20. Juli 2017  ·  26Kommentare  ·  Quelle: axios/axios

Ähnlich wie bei #318 kann ich mit Axios auf dem Knoten keine Post-Anfrage stellen. Aber im Browser scheint der gleiche Code gut zu funktionieren.

const fdata = new FormData();
fdata.append('user', u);
fdata.append('hostnames', n.join(' '));
const host = localStorage.getItem('host');
const port = localStorage.getItem('port');
axios({
  url: `http://${host}:${port}/hosts/remove`,
  method: 'post',
  data: fdata
}).then(response => {
  if (response.status === 200) {
    console.log(response.data);
    console.log('Removed host successfully');
  }
  return null;
}).catch(er => console.log(er));

Mit Unirest funktioniert es:

unirest.post(`http://${host}:${port}/hosts/remove`)
.headers({ 'Content-Type': 'multipart/form-data' })
.field('user', u)
.field('hostnames', h.join(' '))
.end(response => {
  console.log(response.body);
});
  • Axios-Version: v0.16.2
  • Umgebung: Knoten v8.0.0, Windows 8.1

Hilfreichster Kommentar

Dies könnte als Duplikat von #789 angesehen werden.

Ich konnte das Paket form-data mit Axios in nodejs verwenden. Es bietet im Grunde eine FormData ähnliche Schnittstelle. Sie müssen jedoch darauf achten, die generierten Header manuell an Axios zu übergeben. Zum Beispiel:

const axios = require('axios');
const FormData = require('form-data');

const form = new FormData();
// Second argument  can take Buffer or Stream (lazily read during the request) too.
// Third argument is filename if you want to simulate a file upload. Otherwise omit.
form.append('field', 'a,b,c', 'blah.csv');
axios.post('http://example.org/endpoint', form, {
  headers: form.getHeaders(),
}).then(result => {
  // Handle result…
  console.log(result.data);
});

Alle 26 Kommentare

Dies könnte als Duplikat von #789 angesehen werden.

Ich konnte das Paket form-data mit Axios in nodejs verwenden. Es bietet im Grunde eine FormData ähnliche Schnittstelle. Sie müssen jedoch darauf achten, die generierten Header manuell an Axios zu übergeben. Zum Beispiel:

const axios = require('axios');
const FormData = require('form-data');

const form = new FormData();
// Second argument  can take Buffer or Stream (lazily read during the request) too.
// Third argument is filename if you want to simulate a file upload. Otherwise omit.
form.append('field', 'a,b,c', 'blah.csv');
axios.post('http://example.org/endpoint', form, {
  headers: form.getHeaders(),
}).then(result => {
  // Handle result…
  console.log(result.data);
});

Ja, ich habe es mit diesem form-data Paket versucht. Nun, es ist in Ordnung, ich habe die serverseitige API geändert, um stattdessen JSON zu analysieren.

Kann mir bitte jemand zeigen, was in der nodejs-App zu tun ist?

@ar412 Ich habe versucht, unter https://github.com/mzabriskie/axios/issues/1006#issuecomment -320165427 ein Beispiel zu geben. Könnten Sie klarstellen, was Sie fragen?

@binki Wenn axios verwendet wird, um eine Post-Anforderung an ein Restapi mit einigen Daten zu senden, wie kann man diese Daten dann in der Restapi abrufen (die sich in einer Express-Anwendung befindet).

Sie können dies versuchen https://expressjs.com/en/4x/api.html#req @ar412

@ar412 Um mehrteilige Daten in Express zu empfangen, können Sie etwas wie busboy wie in den Dokumenten von body-parser empfohlen . Grundsätzlich hat das nichts mit Axios zu tun, um zu lernen, wie man mit hochgeladenen Dateien in Express umgeht, also fragen Sie besser woanders nach, da Sie diesen Thread entführt haben ;-). Siehe beispielsweise diese Antwort auf SO .

Fehlermeldung erhalten: form.getHeaders() ist keine Funktion

@binki
Hey! Ich habe einen hapi.js-Server, auf dem ich eine in einer Variablen gespeicherte Bilddatei mithilfe von fs.readFile(path) POST stellen möchte.
Ich kann es nicht schaffen, das als FormData() zu senden

Das ist mein Code:

fs.readFile(__dirname+'/../static/lisa_server.jpg', (error, imageData) => {
          var form = new FormData()

            form.append('file', imageData,  {
            filename: 'unicycle.jpg', // ... or:
            filepath: '/../static/lisa_server.jpg',
            contentType: 'image/jpg',
            knownLength: 19806
          })

Dann sende ich das Formular als Hauptteil der Anfrage und setze options['Content-Type'] = 'multipart/form-data'

Könnten Sie helfen?
Sehr geschätzt!

@bstolarz Wenn Sie Buffer , was Sie tun, müssen Sie knownLength . Auch wenn Sie lesen, was Sie geschrieben haben (fehler, kopiert und eingefügt aus den README-Beispielen von filename oder filepath angeben – nicht beides. Die einzigen Dinge, die für Sie möglicherweise sinnvoll sind, sind:

  1. filename ODER filepath
  2. contentType (falls der Server einen bestimmten Content-Type-Wert benötigt, sonst kann er wahrscheinlich weggelassen werden).

Was ich wette, ist, dass die Größe des Bildes, das Sie senden, eine Größe hat, die nicht 19806 weil dieser 19806 etwas ist, das Sie aus einem Beispiel in form-data kopiert haben 's-Dokumente und nicht für Ihre eigenen Daten berechnet. Dies führt wahrscheinlich dazu, dass form-data selbst einen Fehler auslöst oder ungültige Daten in die HTTP-Anfrage schreibt. Haben Sie überprüft, ob die zurückgegebenen Promise axios.post() abgelehnt werden oder ob eine Ausnahme ausgelöst wird? Wenn die Axios-Anforderung abgelehnt wird, überprüfen Sie, ob das Fehlerobjekt einen result Schlüssel hat und überprüfen Sie, falls dies der Fall ist, den err.result.status . Wenn es sich um einen anderen 4xx-Wert als 404 oder 403 handelt, bedeutet dies wahrscheinlich, dass der Server eine fehlerhafte Anfrage ablehnt, die auf eine falsche bekannte Größe zurückzuführen sein könnte.

@binki
Hey, danke für deine Antwort. Ich habe die Dinge korrigiert, die Sie erwähnt haben, also ist mein Code jetzt

fs.readFile(__dirname+'/../static/lisa_server.jpg', (error, imageData) => {
          var form = new FormData()

          form.append('file', imageData, {
               filepath: __dirname+'/../static/lisa_server.jpg',
               contentType: 'image/jpg'

          })

Aber der Server wirft 411 "Länge ist erforderlich" (ich habe auch fs.createReadStream ausprobiert, das anscheinend vollständig von FormData unterstützt wird, aber ich erhalte den gleichen Längenfehler).

@binki
Ich habe es geschafft, die Inhaltslänge des Headers in der untersten Ebene festzulegen, und ich erhalte diesen Fehler nicht mehr.
Jetzt, da ich keine 411 vom Server bekomme, bin ich zurück zu dem Fehler, den ich einmal 400 hatte - "Keine Dateien bereitgestellt".

So sieht die Anfrage aus

Startanfrage

{ adapter: [Function: httpAdapter],
  transformRequest: { '0': [Function: transformRequest] },
  transformResponse: { '0': [Function: transformResponse] },
  timeout: 5000,
  xsrfCookieName: 'XSRF-TOKEN',
  xsrfHeaderName: 'X-XSRF-TOKEN',
  maxContentLength: -1,
  validateStatus: [Function: validateStatus],
  headers:
   { common: { Accept: 'application/json, text/plain, */*' },
     delete: {},
     get: {},
     head: {},
     post: { 'Content-Type': 'application/json' },
     put: { 'Content-Type': 'application/json' },
     patch: { 'Content-Type': 'application/json' },
     'User-Agent': 'trojan server 1.0',
     'X-Origin-Panamera': 'Staging',
     'Content-Length': 25247 },
  baseURL: 'https://letgoar-a.akamaihd.net/api/v1',
  method: 'post',
  url: 'https://<baseDomain>/api/v1/images',
  data:
   FormData {
     _overheadLength: 218,
     _valueLength: 25247,
     _valuesToMeasure: [],
     writable: false,
     readable: true,
     dataSize: 0,
     maxDataSize: 2097152,
     pauseStreams: true,
     _released: false,
     _streams:
      [ '----------------------------677738213014296377492349\r\nContent-Disposition: form-data; name="file"; filename="/Users/brenda/repos/qreator2/qreator/trojan-server/src/static/lisa_server.jpg"\r\nContent-Type: image/jpg\r\n\r\n',
        <Buffer ff d8 ff e0 00 10 4a 46 49 46 00 01 01 01 00 48 00 48 00 00 ff e2 11 2c 49 43 43 5f 50 52 4f 46 49 4c 45 00 01 01 00 00 11 1c 61 70 70 6c 02 00 00 00 ... >,
        [Function: bound ] ],
     _currentStream: null,
     _boundary: '--------------------------677738213014296377492349' },
  'Content-Type': 'multipart/form-data' }

Ich hoffe, Sie überprüfen das. Sieht das für Sie nach einer vernünftigen Bitte aus?

Danke im Voraus

@bstolarz Ich habe mein Bestes getan, um Ihr Problem zu reproduzieren. Ich kann jedoch nicht. Ich habe diesen Code geschrieben, um zu imitieren, was Sie tun. Ich habe jedoch bewusst darauf verzichtet, Content-Length manuell festzulegen. Ich bin überzeugt, dass die Tatsache, dass Sie Content-Length festlegen, möglicherweise mit Ihrem Problem zusammenhängt. Bitte lassen Sie das form-data die Berechnung für Sie übernehmen – deshalb müssen Sie form.getHeaders() anrufen.

Siehe diese Paste: https://gist.github.com/binki/10ac3e91851b524546f8279733cdadad . Vielleicht können Sie die Art und Weise, wie Sie axios.post() oder axios() aufrufen, an mein Beispiel anpassen und es wird für Sie funktionieren?

Wenn weiterhin Probleme auftreten, versuchen Sie, Ihren Code in ein eigenes Skript zu verschieben und dort zu reproduzieren. Es kann Ihnen helfen, das Problem zu lösen. Wenn Sie immer noch nicht weiterkommen, posten Sie bitte den vollständigen Code, einschließlich des Aufrufs an axios() oder axios.post() als Kernstück und verlinken Sie ihn hier, und wenn ich kann, werde ich mir das ansehen.

Es geht immer noch gar nicht...

@rodrigogs Wenn du Hilfe brauchst, musst du genauer sein ;-).

Ich habe diese hilfreiche Recherche zu Axios verfolgt und die endgültige Lösung funktioniert für mich ( Link )

Hier ist das Kopieren/Einfügen davon:

import fs from 'fs';
import FormData from 'form-data';
import axios from 'axios';

let data = fs.createReadStream(__dirname + '/test.jpg');
let form = new FormData();

form.append('type','image');
form.append('media',data,'test.jpg');

function getHeaders(form) {
    return Promise((resolve, reject) => {
        form.getLength((err, length) => {
            if(err) { reject(err); }
            let headers = Object.assign({'Content-Length': length}, form.getHeaders());
            resolve(headers);
         });
    });
}

getHeaders(form)
.then((headers) => {
    return axios.post(url, form, {headers:headers})
})
.then((response)=>{
    console.log(response.data)
})
.catch(e=>{console.log(e)})

@westofpluto , ich erhalte auch den gleichen Fehler. @binki , Idee ?
Der Fehler
form.getHeaders ist keine Funktion

@smplyjr Können Sie mehr Kontext geben und mich wissen lassen, wie Sie form ? Ohne Code können wir nicht sagen, was Sie tun oder Ihnen helfen.

Für nodejs-Benutzer lösen Sie dies mithilfe der querystring lib wie folgt:

const querystring = require('querystring')
axios
  .post(URL, querystring.stringify(data))
  .then((response) => ...)
  .catch((error) => ...)

Wie @heldrida erwähnt, verwenden Sie querystring. So empfiehlt es axios auch hier: https://www.npmjs.com/package/axios#nodejs. Das Paket form-data hat hier alle möglichen Probleme und Sie werden sich am Ende nur die Haare ausreißen, um es zum Laufen zu bringen.

@heldrida @ashok-sc Wie muss ich querystring oder qs , um eine Datei mit Axios hochzuladen? Ich verwende Axios, um Dateien von einem AWS Lambda hochzuladen, und habe von dort offensichtlich keinen Zugriff auf das File- Objekt

@bstolarz Ich habe mein Bestes getan, um Ihr Problem zu reproduzieren. Ich kann jedoch nicht. Ich habe diesen Code geschrieben, um zu imitieren, was Sie tun. Ich habe jedoch bewusst darauf verzichtet, Content-Length manuell festzulegen. Ich bin überzeugt, dass die Tatsache, dass Sie Content-Length festlegen, möglicherweise mit Ihrem Problem zusammenhängt. Bitte lassen Sie das form-data die Berechnung für Sie übernehmen – deshalb müssen Sie form.getHeaders() anrufen.

Siehe diese Paste: https://gist.github.com/binki/10ac3e91851b524546f8279733cdadad . Vielleicht können Sie die Art und Weise, wie Sie axios.post() oder axios() aufrufen, an mein Beispiel anpassen und es wird für Sie funktionieren?

Wenn weiterhin Probleme auftreten, versuchen Sie, Ihren Code in ein eigenes Skript zu verschieben und dort zu reproduzieren. Es kann Ihnen helfen, das Problem zu lösen. Wenn Sie immer noch nicht weiterkommen, posten Sie bitte den vollständigen Code, einschließlich des Aufrufs an axios() oder axios.post() als Kernstück und verlinken Sie ihn hier, und wenn ich kann, werde ich mir das ansehen.

Danke, Mann. Das Hinzufügen von Content-Length hat mein Problem gelöst, jetzt kann ich axios backend-2-backend-Aufrufe mit FormData verwenden:
const options = { method: 'POST', url: myUrl, data: justJsonBody, transformRequest: [function (data, headers) { const formData = convertToFormData(data); // returrns ForrmData from form-data headers['Content-Type'] = formData.getHeaders()['content-type']; headers['Content-Length'] = formData._overheadLength; return formData; }] };

Dies könnte als Duplikat von #789 angesehen werden.

Ich konnte das Paket form-data mit Axios in nodejs verwenden. Es bietet im Grunde eine FormData ähnliche Schnittstelle. Sie müssen jedoch darauf achten, die generierten Header manuell an Axios zu übergeben. Zum Beispiel:

const axios = require('axios');
const FormData = require('form-data');

const form = new FormData();
// Second argument  can take Buffer or Stream (lazily read during the request) too.
// Third argument is filename if you want to simulate a file upload. Otherwise omit.
form.append('field', 'a,b,c', 'blah.csv');
axios.post('http://example.org/endpoint', form, {
  headers: form.getHeaders(),
}).then(result => {
  // Handle result…
  console.log(result.data);
});

Ein anderer Weg hierher. Auf diese Weise können Sie Proxy-Agenten und andere Konfigurationen hinzufügen:

const axios = require('axios');
const FormData = require('form-data');
const ProxyAgent = require('proxy-agent');

const form = new FormData();
// Second argument  can take Buffer or Stream (lazily read during the request) too.
// Third argument is filename if you want to simulate a file upload. Otherwise omit.
form.append('field', 'a,b,c', 'blah.csv');
axios({
  method: 'POST',
  url: 'http://example.org/endpoint',
  data: form,
  agent: new ProxyAgent("https://username:[email protected]:8080"),
  headers: bodyFormData.getHeaders()
}).then(result => {
  // Handle result…
  console.log(result.data);
});

Das funktioniert bei mir.

// ES6
import axios from 'axios';
import FormData from 'form-data';
import fs from 'fs';

FormData.prototype.getHeadersWithContentLength = function getHeadersWithContentLength() {
  return new Promise((resolve, reject) => {
    this.getLength((err, length) =>
      err ? reject(err) : resolve({ ...this.getHeaders(), 'Content-Length': length })
    )
  })
}

const payload = new FormData();
const form = new formidable.IncomingForm();

form.parse(req, (err, fields, { file }) => {
  if (err) return;

  payload.append("file", fs.createReadStream(file.path), {
    filename: file.name,
    contentType: file.type
  });

  payload.getHeadersWithContentLength().then(headers => {
    api
      .post(endpoint, payload, { headers })
      .then(({ data }) => data)
      .then(data => res.json({ data }));
  });
});

Danke an alle Mitwirkenden dieses Beitrags. Nachdem ich stundenlang Probleme damit hatte, mein form-data Formular mit Axios an ein Backend zu senden, das es in einen Amazon-Bucket postet, stellte sich heraus, dass die Lösung content-length manuell festgelegt wurde.

Für alle anderen, die Probleme mit meinem Code haben, kann es vielleicht dem nächsten in der Reihe helfen, der Probleme hat, dies zum Laufen zu bringen :)

const axios = require('axios');
const FormData = require('form-data');

// Where buffer is a file
formData.append('file', buffer);

// Added a promise version like seen in earlier comments to get this
const contentLength = await formData.getLength();

await axios(`<ENDPOINT>`, {
    method: 'POST',
    baseURL: <BASE_URL>,
    params: {
        fileName: '<FILE_NAME>.png'
    },
    headers: {
        authorization: `Bearer <TOKEN>`,
        ...formData.getHeaders(),
        'content-length': contentLength
    },
    data: formData
});

Nachdem ich stundenlang Probleme damit hatte, mein form-data Formular mit Axios an ein Backend zu senden, das es in einen Amazon-Bucket postet, stellte sich heraus, dass die Lösung content-length manuell festgelegt wurde.

Jawohl. Ich und ein Kollege von mir verbrachten auch mehrere Stunden damit, Dateien an ein Backend zu senden, das antwortete, dass keine Daten übermittelt wurden, obwohl dies offensichtlich der Fall war, da wir die Anfrage verfolgen und den Inhalt sehen konnten. Das Problem war der fehlende Header mit Inhaltslänge.

Als Hinweis: Wenn Sie FormData einen Puffer hinzufügen, ist es in Ordnung, wenn Sie formData.getLengthSync() aufrufen, aber wenn Sie es mit einem Stream zu tun haben, müssen Sie die Datei zuerst mit fs.statSync(filePath).size oder die volle Größe auf andere Weise erhalten (wie aus einem Inhaltslängen-Header von einem Upstream), zum Beispiel wenn der Stream von einer Anfrage oder einem Socket oder was auch immer kommt. Wenn Ihr Stream stattdessen von der Festplatte kommt, gibt fs.statSync(filePath).size die Größe in Bytes an, sodass Sie ihn beim Anhängen an FormData in bekannter Länge hinzufügen können:

formData.append("file", fs.createReadStream(filePath), { filename: 'whatever.pdf', knownLength: fs.statSync(filePath).size });

Natürlich können alle Sync-Methoden auf async-Methoden und das Schlüsselwort await umgestellt werden.

// Added a promise version like seen in earlier comments to get this
const contentLength = formData.getLength();

Ich schätze, Sie haben vor formData tatsächlich ein await vergessen...

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen