Geonode logo
Geonode Team

Geonode Team

Aktualisiert: 7. Oktober 2026

Veröffentlicht: 02.09.2026

So senden Sie eine POST-Anfrage mit curl (+Beispiele)

`curl -d "key=value" https://example.com` sendet einen POST-Request. Das ist die grundlegende Antwort, und genau darin liegt auch die Ursache für den häufigsten Fehler, auf den Nutzer als Nächstes stoßen. Der Header „`-d`“ legt den Inhaltstyp „form-encoded“ fest. Wenn Sie JSON-Daten damit senden und diesen Header weglassen, werden viele APIs Ihre Anfrage mit einem 415-Fehler zurückweisen. Dieser Leitfaden behandelt Formulardaten, JSON – einschließlich des Abkürzungswegs, den die meisten Nutzer nicht kennen –, Datei-Uploads und die Frage, wie man herausfindet, welche der verschiedenen Datenoptionen man tatsächlich benötigt.

Der Hinweis, den wir kurz halten, da er hier kaum relevant ist: Wir sind Geonode und verkaufen Proxys. Für eine POST-Anfrage ist unser Zutun nicht erforderlich. Alles, was im Folgenden beschrieben wird, funktioniert über Ihre eigene Verbindung zu Ihren eigenen Endpunkten. Proxys kommen erst viel später ins Spiel, und gegen Ende gibt es einen kurzen Hinweis auf die eine Sache, die sich tatsächlich ändert, wenn Sie einen POST-Befehl über einen Proxy senden – und das ist nicht das, was die meisten Leute erwarten.

Grundlagen

curl -d "name=Ada&role=engineer" https://api.example.com/users

Das curl-Handbuch beschreibt „-d, --data

“ wie folgt: „Sendet die angegebenen Daten an einen Server. Bei HTTP(S) erfolgt dies mit der POST-Methode, genau wie bei einem Browser, wenn ein Benutzer ein HTML-Formular ausgefüllt und auf die Schaltfläche ‚Absenden‘ geklickt hat. Diese Option bewirkt, dass curl die Daten unter Verwendung des Content-Types application/x-www-form-urlencoded

an den Server übermittelt.“

Zwei Dinge geschehen automatisch, und beide sind von Bedeutung.

**-d

impliziert POST.** Sie benötigen -X POST

nicht, und das Hinzufügen ändert nichts, außer bei der Umleitungsverarbeitung, wo -X

auf jeden Hop angewendet wird.

**-d

setzt Content-Type: application/x-www-form-urlencoded

.** Dies ist bei Formularübermittlungen korrekt, bei fast allem anderen jedoch falsch.

Sie können -d

wiederholen, und curl fügt die Teile zusammen: Im Handbuch heißt es: „Die Verwendung von -d name=daniel -d skill=lousy

würde einen POST-Chunk erzeugen, der wie name=daniel&skill=lousy

aussieht.“

JSON senden

Die häufigste praktische Anwendung – und hier treten auch die Fehler auf.

Die explizite Methode:

curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"name":"Ada","role":"engineer"}'

Die Abkürzung, die die meisten noch nicht kennen. curl verfügt über eine spezielle Option „--json“, die wie folgt dokumentiert ist: „Sendet die angegebenen JSON-Daten in einer POST-Anfrage an den HTTP-Server. --json dient als Abkürzung für die Übergabe dieser drei Optionen: --data-binary [arg], --header "Content-Type: application/json", --header "Accept: application/json".“

curl --json '{"name":"Ada","role":"engineer"}' https://api.example.com/users

Drei Optionen in einer – dabei werden sowohl „Accept“ als auch „Content-Type“ gesetzt, was in der Regel genau das ist, was Sie wollten. Mit „@“ kann auch aus einer Datei oder über stdin gelesen werden:

curl --json @payload.json https://api.example.com/users
cat payload.json | curl --json @- https://api.example.com/users

Ein ehrlicher Hinweis aus dem Handbuch: „Es wird nicht überprüft, ob die übergebenen Daten tatsächlich JSON sind oder ob die Syntax korrekt ist.“ Es werden Header gesetzt, aber keine Validierung durchgeführt. Ein fehlerhafter Body wird dennoch mit dem Inhaltstyp JSON gesendet, und die Fehlermeldung des Servers bezieht sich dann auf Ihr JSON und nicht auf curl.

Die von ihm gesetzten Header „können wie gewohnt mit --header überschrieben werden“, sodass Sie die Abkürzung beibehalten und einen Teil davon anpassen können.

Einfache Anführungszeichen sind wichtig. Setzen Sie JSON-Inhalte in einfache Anführungszeichen, damit die Shell $ nicht auflöst oder die doppelten Anführungszeichen darin interpretiert. Wenn Ihr JSON auch einfache Anführungszeichen enthält, speichern Sie es in einer Datei.

Die fünf Datenoptionen und wann sie jeweils verwendet werden sollten

Dies ist der Teil, der die meisten Unklarheiten beseitigt, da curl über mehrere Varianten von „--data“ verfügt, die sich in bestimmten Punkten unterscheiden.

OptionFestgelegter InhaltstypIst „@“ speziell?ZeilenumbrücheVerwendung für
-d / --dataform-urlencodedJa, liest eine DateiEntferntFormularübermittlungen
--data-rawform-urlencodedNeinEntferntDaten, die mit @ beginnen
--data-binaryform-urlencodedJaBeibehaltenDateien, exakte Bytes
--data-urlencodeform-urlencodedJaKodiertWerte mit Sonderzeichen
--jsonapplication/jsonJaBeibehaltenJSON-Inhalte

--data-raw gibt es aus einem einzigen Grund: Im Handbuch heißt es, dass diese Methode Daten „ähnlich wie --data, jedoch ohne die spezielle Interpretation des Zeichens @“ übermittelt. Wenn Ihre Daten wörtlich mit @ beginnen – eine E-Mail-Adresse, ein Handle, eine Erwähnung –, versucht -d, diese als Dateinamen zu interpretieren, was zu verwirrenden Fehlern führt. Das eigene Beispiel lautet curl --data-raw "@at@at@".

--data-binary ist die richtige Endpunktadresse für Dateien. Aus dem Handbuch: „Senden Sie Daten genau wie angegeben, ohne jegliche zusätzliche Verarbeitung … Zeilenumbrüche und Wagenrückläufe bleiben erhalten, und es werden niemals Konvertierungen vorgenommen.“ Beachten Sie, dass standardmäßig weiterhin application/x-www-form-urlencoded gesendet wird. Wenn Sie also beliebige Binärdaten senden, empfiehlt das Handbuch, dies zu überschreiben: -H "Content-Type: application/octet-stream".

Aus diesem Grund kann -d @file.json zu subtilen Fehlern führen: Zeilenumbrüche werden entfernt. Bei JSON spielt das normalerweise keine Rolle; bei allem, wo Leerzeichen von Bedeutung sind, ist es jedoch entscheidend. --data-binary @file.json oder --json @file.json ist die sicherere Form.

--data-urlencode verarbeitet Werte, die &, =, Leerzeichen oder andere Zeichen enthalten, die die Formularcodierung stören würden. Das Handbuch dokumentiert mehrere Syntaxen, und die gewünschte ist fast immer name=content, die den Inhalt URL-kodiert und den Namen unverändert lässt:

curl --data-urlencode "comment=hello & goodbye = fine" https://example.com/post

Ohne diese Funktion würde „&“ als Feldtrennzeichen interpretiert und Ihr Kommentar würde stillschweigend abgeschnitten werden. Es gibt außerdem „name@filename“, das den Inhalt aus einer Datei lädt, ihn URL-kodiert und „=“ an den Namen anhängt.

Datei-Uploads und Multipart-Formulare

Für echte Datei-Uploads ist „-F“ die richtige Wahl; dies funktioniert anders als „-d“.

Aus dem Handbuch: „-F, --form <name=content> … simulieren ein ausgefülltes Formular, bei dem der Benutzer auf die Schaltfläche ‚Senden‘ geklickt hat. Dadurch sendet curl POST-Daten mit dem Content-Type multipart/form-data gemäß RFC 2388.“

curl -F "file=@report.pdf" -F "title=Q3 Report" https://api.example.com/upload

Der Unterschied zwischen „@“ und „<“ ist wissenswert, da er nicht intuitiv ist. Aus dem Handbuch: „Um zu erzwingen, dass der ‚content‘-Teil eine Datei ist, setze dem Dateinamen das Symbol @ voran. Um den ‚content‘-Teil aus einer Datei zu beziehen, setze dem Dateinamen das Symbol < voran. Der Unterschied zwischen @ und < besteht dann darin, dass @ bewirkt, dass eine Datei als Datei-Upload an den Beitrag angehängt wird, während < ein Textfeld erstellt und den Inhalt für dieses Textfeld aus einer Datei abruft.“

@ lädt also eine Datei als Datei hoch; < übermittelt den Inhalt einer Datei als Wert eines Textfelds.

So legen Sie einen Inhaltstyp für ein Element fest:

curl -F "file=@data.csv;type=text/csv" https://api.example.com/upload

Und wenn Sie einen Literalwert benötigen, der mit @ oder < beginnt, verwenden Sie --form-string, da hier keines der beiden Zeichen interpretiert wird.

Legen Sie Content-Type: multipart/form-data nicht selbst fest. curl generiert diese URL einschließlich eines Begrenzungsparameters, und ein Überschreiben führt zu einer Anfrage, die der Server nicht auswerten kann – eine sehr häufige Ursache für unerklärliche 400er- und 415er-Fehler.

Für einen einfachen PUT-Aufruf einer Datei ist „-T“ die einfachere Lösung: „Lade die angegebene lokale Datei an die Remote-URL hoch … Wenn diese Option mit einer HTTP(S)-URL verwendet wird, kommt die PUT-Methode zum Einsatz.“

Authentifizierung und Header

curl --json '{"a":1}' \
  -H "Authorization: Bearer eyJhbG..." \
  https://api.example.com/items

-H ist wiederholbar und überschreibt die Standardeinstellungen von curl, einschließlich derjenigen, die --json festlegt.

Für die Basic-Authentifizierung: -u user:password – oder allein -u user , wodurch curl eine Eingabeaufforderung anzeigt, sodass das Passwort nicht im Verlauf Ihrer Shell gespeichert wird. Im Handbuch wird darauf hingewiesen, dass „auf Systemen, auf denen dies funktioniert, curl das angegebene Optionsargument in Prozesslisten verbirgt“, wobei hinzugefügt wird, dass „dies nicht ausreicht, um Anmeldedaten zu schützen“.

Bei einer sitzungsbasierten API sollten Sie Cookies erfassen und wiederverwenden:

curl -c jar.txt -d "user=ada&pass=secret" https://example.com/login
curl -b jar.txt --json '{"a":1}' https://example.com/api/items

Fehlerbehebung bei einem POST, der nicht funktioniert

Eine kurze Anleitung, die fast alle Probleme löst.

Sehen Sie sich genau an, was Sie gesendet haben:

curl -v --json '{"a":1}' https://api.example.com/items 2>&1 | grep -E '^[<>]'

Zeilen, die mit „> “ beginnen, sind Ihre Anfrage, „< “ ist die Antwort. Vergewissern Sie sich, dass die Methode, die „Content-Type “ und der Body Ihren Absichten entsprechen. Ein überraschend großer Teil der Meldungen „Die API funktioniert nicht“ lässt sich auf diese Weise beheben.

Lesen Sie den Statuscode und den Fehlertext:

curl -sS -o body.txt -D headers.txt --json '{"a":1}' https://api.example.com/items
head -1 headers.txt; head -c 300 body.txt

Interpretieren Sie die häufigsten Fehler:

StatusBedeutet in der Regel
400Fehlerhafter Textkörper oder fehlendes Pflichtfeld
401Fehlende oder ungültige Anmeldedaten
403Authentifiziert, aber keine Berechtigung
405Der Endpunkt akzeptiert keine POST-Anfragen – überprüfe die URL und die Methode
413Textkörper zu groß
415Falscher „Content-Type
“ – der klassische „-d
“-Fehler bei JSON
422Inhaltstyp in Ordnung, Daten haben die Validierung nicht bestanden

Der Unterschied zwischen 415 und 422 sollte man sich unbedingt verinnerlichen: 415 bedeutet, dass der Wrapper falsch ist, 422 bedeutet, dass der Inhalt falsch ist. Wir haben dies ausführlich unter Was ist ein 415-Statuscode behandelt.

Machen Sie Fehler in Skripten deutlich sichtbar:

curl --fail-with-body --silent --show-error \
     --connect-timeout 5 --max-time 30 \
     --json @payload.json https://api.example.com/items

--fail-with-body gibt bei HTTP-Fehlern einen Exit-Wert ungleich Null zurück und gibt dennoch den Antworttext aus – genau das, was Sie wollen, wenn die API nützliche JSON-Fehlermeldungen zurückgibt. Einfaches --fail verwirft den Antworttext und damit auch die Erklärung.

Eine Browser-Anfrage in einen curl-Befehl umwandeln

Der schnellste Weg, einen POST-Befehl zu reproduzieren, der im Browser funktioniert, in Ihrem Code jedoch nicht – und eine Technik, die die meisten erst viel später entdecken, als sie sollten.

Kopieren Sie ihn aus den Entwicklertools. Öffnen Sie in Chrome, Firefox und Safari die Registerkarte „Netzwerk“, suchen Sie die Anfrage, klicken Sie mit der rechten Maustaste darauf und wählen Sie „Als cURL kopieren“. Sie erhalten einen vollständigen Befehl mit allen Headern, Cookies und dem Body, die der Browser gesendet hat. Fügen Sie ihn in ein Terminal ein, und er sollte sich identisch verhalten.

Das beantwortet sofort die Frage, die hinter den meisten Debugging-Sitzungen steht: Liegt das Problem bei der Anfrage oder bei meinem Code? Wenn der kopierte Befehl funktioniert und deiner nicht, liegt der Unterschied in dem, was du sendest, und du hast nun beide Versionen nebeneinander zum Vergleich.

Dann reduziere ihn. Ein kopierter Befehl enthält in der Regel dreißig Header, von denen die meisten irrelevant sind. Entferne sie nach und nach und führe den Befehl erneut aus, bis er fehlschlägt. Was übrig bleibt, ist das Minimum, das der Server tatsächlich benötigt, und genau das gehört in deine Anwendung:

curl 'https://api.example.com/items' \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer eyJhbG...' \
  --data-raw '{"name":"Ada"}'

Beachten Sie, dass Browser „--data-raw“ anstelle von „-d“ exportieren, gerade weil ein Body, der mit „@“ beginnt, andernfalls fälschlicherweise als Dateiname interpretiert würde.

Achten Sie auf zwei Dinge, die beim Kopieren verloren gehen. Cookies werden als wörtlicher Header mitgeschickt und verfallen. Und alles, was die Seite in JavaScript berechnet hat – ein CSRF-Token, eine Signatur, ein aus einem Zeitstempel abgeleiteter Wert – wird als feste Zeichenkette in den kopierten Befehl eingebettet, sodass er einmal funktioniert und dann nicht mehr. Wenn eine reproduzierte Anfrage zunächst erfolgreich ist und dann beim zweiten Durchlauf fehlschlägt, ist dies fast immer der Grund dafür, und die Lösung besteht darin, das Token abzurufen, anstatt es fest zu codieren.

Umgekehrt gibt es mehrere Tools, die einen curl-Befehl in Code für die meisten Sprachen konvertieren. Dies ist eine sinnvolle Methode, um von einem funktionierenden Befehl zu einem funktionierenden Client zu gelangen, ohne die Header manuell neu eingeben zu müssen.

POST-Anrufe über einen Proxy

Kurz gesagt: Der wichtige Punkt ist eher eine Warnung als eine technische Anleitung.

curl -x http://user:pass@proxy.example.com:9000 \
     --json '{"a":1}' https://api.example.com/items

Die Funktionsweise bleibt unverändert. Was sich ändert, ist die Strategie für Wiederholungsversuche, und genau darüber sollten Sie nachdenken, bevor Sie „--retry “ hinzufügen.

POST ist im Allgemeinen nicht idempotent. Wenn man die Anfrage zweimal sendet, können zwei Datensätze entstehen. Die „--retry “-Funktion von curl wird standardmäßig nur bei vorübergehenden Störungen ausgelöst, aber „--retry-all-errors “ erweitert diesen Anwendungsbereich erheblich – und über einen Proxy bedeutet ein 5xx-Fehler oft, dass das Ziel den Zugriff verweigert hat, anstatt dass es sich um eine vorübergehende Störung handelte. Ein erneuter Versuch ist bestenfalls sinnlos und führt im schlimmsten Fall zu einem doppelten Schreibvorgang.

Ein Timeout ist kein Beweis für einen Fehler. Wenn eine Anfrage ein Timeout erreicht, nachdem der Server sie bereits empfangen hat, ist der Vorgang möglicherweise bereits abgeschlossen, während du eine Fehlermeldung gesehen hast. Über einen Proxy gibt es einen zusätzlichen Hop, bei dem dies passieren kann. Wenn der Vorgang wichtig ist, verwende zur Sicherheit einen Idempotenzschlüssel – die meisten seriösen APIs unterstützen einen solchen –, anstatt dich auf die Wiederholungslogik zu verlassen.

Und prüfen Sie, an welcher Stelle Sie abgelehnt wurden. %{http_connect} meldet die Antwort des Proxys auf den CONNECT-Befehl getrennt vom Status des Zielservers:

curl -sS -o /dev/null -x "$PROXY" \
  -w 'connect=%{http_connect} status=%{response_code}\n' \
  --json '{"a":1}' https://api.example.com/items

„

connect=407 “ bedeutet, dass der Proxy Anmeldedaten verlangt hat. „connect=200 status=403 “ bedeutet, dass der Proxy funktioniert hat und das Ziel die Anfrage abgelehnt hat. Unterschiedliche Probleme, unterschiedliche Lösungen.

Häufig gestellte Fragen

Wie sende ich eine POST-Anfrage mit curl?

curl -d "key=value" URL. Die Option „-d“ impliziert bereits POST, daher ist „-X POST“ überflüssig. Außerdem wird „Content-Type: application/x-www-form-urlencoded“ gesetzt, was für Formularübermittlungen korrekt, für JSON jedoch falsch ist.

Wie sende ich JSON per POST mit curl? „

curl --json '{"key":"value"}' URL“ ist die Kurzform – sie setzt „--data-binary“ sowie die Header „Content-Type“ und „Accept“ auf „application/json“. Die längere Form lautet -X POST -H "Content-Type: application/json" -d '...'. Beachten Sie, dass --json Ihr JSON nicht validiert.

Warum erhalte ich von curl den Fehler „415 Unsupported Media Type“?

Fast immer liegt es daran, dass Sie -d mit einem JSON-Body verwendet haben, ohne den Content-Type festzulegen. -d sendet form-encoded, und eine API, die JSON erwartet, lehnt dies ab. Verwenden Sie --json oder fügen Sie -H "Content-Type: application/json" hinzu.

Was ist der Unterschied zwischen -d und --data-raw?

-d interpretiert ein vorangestelltes „@“ als „aus dieser Datei lesen“. --data-raw tut dies nicht; daher benötigen Sie diese Option, wenn Ihre Daten mit „@“ beginnen – beispielsweise bei einer E-Mail-Adresse oder einem Handle. Ansonsten verhalten sich beide Optionen identisch.

Wie lade ich eine Datei mit curl POST hoch?

„curl -F "file=@document.pdf" URL“, was „multipart/form-data“ sendet. Verwenden Sie „@“, um die Datei als Anhang beizufügen, und „<“, um ihren Inhalt als Wert eines Textfelds zu senden. Setzen Sie den Header „Content-Type“ nicht selbst – curl generiert ihn mit der erforderlichen Begrenzung.

Wie sende ich POST-Daten aus einer Datei?

Verwende „curl --json @payload.json URL“ für JSON oder „--data-binary @file“ für exakte Byte-Daten einschließlich Zeilenumbrüche. Vermeide „-d @file“, wenn Leerzeichen eine Rolle spielen, da „-d“ Zeilenumbrüche und Wagenrückläufe entfernt.

Wie sende ich einen Wert per POST, der ein Und-Zeichen enthält?

Verwende --data-urlencode "field=value with & inside". Bei einfachem -d wird das Und-Zeichen als Feldtrennzeichen interpretiert und dein Wert an dieser Stelle stillschweigend abgeschnitten.

Sollte ich einen fehlgeschlagenen POST-Versuch wiederholen?

Mit Vorsicht. POST ist im Allgemeinen nicht idempotent, sodass ein erneuter Versuch zu einem Duplikat führen kann – und ein Timeout ist kein Beweis dafür, dass der Server die Anfrage nicht verarbeitet hat. Verwenden Sie einen Idempotenzschlüssel, sofern die API dies unterstützt, und seien Sie vorsichtig mit „--retry-all-errors“, insbesondere über einen Proxy, wo ein 5xx-Code oft eher eine Ablehnung als einen vorübergehenden Fehler bedeutet.

Fazit

Das gesamte Thema lässt sich auf eine Frage reduzieren: Welchen Inhaltstyp erwartet der Endpunkt, und sendet Ihr Befehl diesen?

-d sendet „form-encoded“, was für Formularübermittlungen richtig, für JSON jedoch falsch ist – und genau diese eine Diskrepanz ist die Ursache für die meisten 415-Fehler, auf die Nutzer stoßen. --json ist stattdessen die richtige Option, die jedoch kaum bekannt ist: ein Flag, das die Verarbeitung des Body sowie beide Header festlegt, mit @-Unterstützung für Dateien und stdin.

Darüber hinaus gibt es Varianten aus bestimmten Gründen, die man sich merken sollte. --data-raw, wenn Ihre Daten mit @ beginnen. --data-binary, wenn Zeilenumbrüche eine Rolle spielen. --data-urlencode, wenn ein Wert Zeichen enthält, die die Formularcodierung stören würden. -F für tatsächliche Datei-Uploads, mit @ zum Anhängen einer Datei und < zum Auslesen eines Textfelds aus einer Datei.

Und wenn etwas fehlschlägt, führen Sie den Befehl mit -v aus und lesen Sie die Zeilen unter >, bevor Sie irgendetwas ändern. Die von Ihnen gesendete Anfrage ist häufig nicht die Anfrage, die Sie zu senden glaubten, und genau in dieser Diskrepanz liegt der Hauptgrund für die Verwirrung in diesem Bereich.