Bu konuyla pek ilgisi olmadığı için kısa tutacağımız açıklama: Biz Geonode olarak proxy satışı yapıyoruz. Bir POST isteği için bizim tarafımızdan hiçbir şeye gerek yoktur. Aşağıdaki her şey, kendi bağlantınız üzerinden kendi uç noktalarınıza karşı çalışır. Proxy'ler ancak çok daha sonra devreye girer ve yazının sonuna doğru, bir proxy üzerinden POST yaptığınızda gerçekten değişen tek şey hakkında kısa bir not bulunmaktadır — ki bu, çoğu kişinin beklediği şey değildir.
Temel Bilgiler
curl -d "name=Ada&role=engineer" https://api.example.com/users
curl kılavuzu, -d, --data
komutunu şöyle açıklamaktadır: "Belirtilen verileri bir sunucuya gönderir. HTTP(S) için bu işlem, bir kullanıcı HTML formunu doldurup gönder düğmesine bastığında tarayıcının yaptığı gibi POST yöntemi ile gerçekleştirilir. Bu seçenek, curl'ün verileri application/x-www-form-urlencoded
içerik türü kullanarak sunucuya iletmesini sağlar."
İki şey otomatik olarak gerçekleşir ve her ikisi de önemlidir.
**-d
, POST yöntemini ima eder.** -X POST
eklemenize gerek yoktur; bunu eklemek, her atlamada -X
'in uygulandığı yönlendirme işleme dışında hiçbir şeyi değiştirmez.
**-d
, Content-Type: application/x-www-form-urlencoded
değerini ayarlar.** Bu, form gönderimleri için doğrudur ancak diğer hemen hemen her durum için yanlıştır.
-d
komutunu tekrarlayabilirsiniz; curl, parçaları birleştirir: kılavuzda "-d name=daniel -d skill=lousy
kullanılması, name=daniel&skill=lousy
gibi görünen bir POST parçası oluşturur" şeklinde belirtilmiştir.
JSON Gönderme
En yaygın gerçek kullanım alanı ve hataların ortaya çıktığı yer.
Açık yöntem:
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"name":"Ada","role":"engineer"}'
Çoğu kişinin bilmediği kısayol. curl'da, şu şekilde belgelenmiş özel bir --json seçeneği vardır: "Belirtilen JSON verilerini bir POST isteği ile HTTP sunucusuna gönderir. --json, şu üç seçeneği aktarmak için bir kısayol görevi görür: --data-binary [arg], --header "Content-Type: application/json", --header "Accept: application/json"."
curl --json '{"name":"Ada","role":"engineer"}' https://api.example.com/users
Üç seçeneği bir arada sunar ve Accept ile Content-Type ayarlarını yapar; bu genellikle istediğiniz şeydir. Ayrıca @ ile bir dosyadan veya stdin'den okur:
curl --json @payload.json https://api.example.com/users
cat payload.json | curl --json @- https://api.example.com/users
Kılavuzda yer alan dürüst bir uyarı: "İletilen verilerin gerçek JSON olup olmadığı veya sözdiziminin doğru olup olmadığı doğrulanmaz." Bu komut başlıkları ayarlar; doğrulama yapmaz. Biçimi bozuk bir gövde yine de JSON içerik türüyle gönderilir ve sunucunun şikayeti curl ile ilgili değil, sizin JSON'unuzla ilgili olacaktır.
Ayarladığı başlıklar "her zamanki gibi --header ile geçersiz kılınabilir", bu sayede kısayolu koruyup bir kısmını ayarlayabilirsiniz.
Tek tırnak işaretleri önemlidir. Kabuğun $ ifadesini genişletmemesi veya içindeki çift tırnak işaretlerini yorumlamaması için JSON gövdelerini tek tırnak işaretleri içine alın. JSON'unuzda tek tırnak işaretleri de varsa, bunu bir dosyaya kaydedin.
Beş Veri Seçeneği ve Her Birinin Ne Zaman Kullanılacağı
Bu bölüm, en çok kafa karışıklığına yol açan konuyu açıklığa kavuşturur; zira curl’da belirli yönlerden farklılık gösteren birkaç --data varyantı bulunmaktadır.
| Seçenek | İçerik türü ayarı | @ özel mi? | Satır sonları | Ne için kullanılır |
|---|---|---|---|---|
-d / --data | form-urlencoded | Evet, bir dosyayı okur | Kaldırılır | Form gönderimleri |
--data-raw | form-urlencoded | Hayır | Kaldırılır | @ ile başlayan veriler |
--data-binary | form-urlencoded | Evet | Korunur | Dosyalar, tam baytlar |
--data-urlencode | form-urlencoded | Evet | Kodlanmış | Özel karakterler içeren değerler |
--json | application/json | Evet | Korunur | JSON gövdeleri |
--data-raw tek bir nedenden dolayı mevcuttur: kılavuzda, bu yöntemin verileri "--data'a benzer şekilde, ancak @ karakterinin özel yorumlanması olmadan" gönderdiği belirtilmektedir. Eğer verileriniz @ ile başlıyorsa — bir e-posta adresi, bir kullanıcı adı, bir bahsetme — -d bunu bir dosya adı olarak okumaya çalışacak ve kafa karıştırıcı bir şekilde hata verecektir. Kendi örnekleri şöyledir: curl --data-raw "@at@at@".
--data-binary dosyalar için kullanılması gereken yöntemdir. Kılavuzda şöyle yazıyor: "Verileri, hiçbir ek işleme tabi tutmadan tam olarak belirtildiği şekilde gönderin... satır sonları ve satır başı karakterleri korunur ve hiçbir dönüştürme işlemi yapılmaz." Varsayılan olarak hâlâ application/x-www-form-urlencoded gönderildiğini unutmayın; bu nedenle, rastgele ikili veriler gönderiyorsanız, kılavuzda belirtildiği gibi bunu geçersiz kılmanız gerekir: -H "Content-Type: application/octet-stream".
İşte bu yüzden -d @file.json gibi adresler ince bir şekilde hataya neden olabilir: satır sonları kaldırılır. JSON için bu genellikle önemli değildir; ancak boşlukların önemli olduğu durumlarda önemlidir. --data-binary @file.json veya --json @file.json daha güvenli biçimlerdir.
--data-urlencode, &, =, boşluklar veya form kodlamasını bozabilecek diğer her türlü öğeyi içeren değerleri işler. Kılavuzda çeşitli sözdizimleri belgelenmiştir ve sizin ihtiyacınız olanı neredeyse her zaman name=content şeklindedir; bu, içeriği URL kodlamasına tabi tutar ve adı olduğu gibi bırakır:
curl --data-urlencode "comment=hello & goodbye = fine" https://example.com/post
Bu kod olmadan, & bir alan ayırıcısı olarak algılanır ve yorumunuz fark edilmeden kesilir. Ayrıca, içeriği bir dosyadan yükleyen, URL kodlaması uygulayan ve ismin sonuna = ekleyen name@filename komutu da mevcuttur.
Dosya Yüklemeleri ve Çok Parçalı Formlar
Gerçek dosya yüklemeleri için -F seçeneği kullanılır ve bu, -d adresinden farklı şekilde çalışır.
Kılavuzda şöyle belirtilmiştir: "-F, --form <name=content> ... kullanıcının gönder düğmesine bastığı, doldurulmuş bir formu taklit eder. Bu, curl'un RFC 2388'e göre Content-Type multipart/form-data kullanarak POST verisi göndermesini sağlar."
curl -F "file=@report.pdf" -F "title=Q3 Report" https://api.example.com/upload
@ ve < arasındaki farkı öğrenmek önemlidir, çünkü bu fark sezgisel değildir. Kılavuzda şöyle yazmaktadır: "‘content’ kısmının bir dosya olmasını zorlamak için, dosya adının başına @ işaretini ekleyin. Dosyadan içerik kısmını almak için, dosya adının başına < sembolünü ekleyin. @ ile < arasındaki fark şudur: @, bir dosyanın gönderiye dosya yüklemesi olarak eklenmesini sağlarken, < bir metin alanı oluşturur ve bu metin alanının içeriğini bir dosyadan alır."
Yani @ bir dosyayı dosya olarak yükler; < ise bir dosyanın içeriğini metin alanı değeri olarak gönderir.
Bir parçaya içerik türü ayarlamak için:
curl -F "file=@data.csv;type=text/csv" https://api.example.com/upload
@ veya < ile başlayan bir sabit değere ihtiyacınız varsa, bu karakterleri yorumlamayan --form-string adresini kullanın.
Content-Type: multipart/form-data değerini kendiniz ayarlamayın. curl, bu değeri bir sınır parametresi dahil ederek oluşturur ve bu parametreyi geçersiz kılmak, sunucunun çözümleyemediği bir istek oluşturur — bu, açıklanamayan 400 ve 415 hatalarının çok yaygın bir nedenidir.
Bir dosyayı basit bir PUT işlemiyle yüklemek için -T daha basittir: "Belirtilen yerel dosyayı uzak URL'ye yükle... Bu seçenek bir HTTP(S) URL'siyle kullanılırsa, PUT yöntemi kullanılır."
Kimlik Doğrulama ve Başlıklar
curl --json '{"a":1}' \
-H "Authorization: Bearer eyJhbG..." \
https://api.example.com/items
-H
komutu tekrarlanabilir ve --json
ile belirlenenler de dahil olmak üzere curl’ün varsayılan ayarlarını geçersiz kılar.
Temel kimlik doğrulama için -u user:password
— ya da tek başına -u user
kullanın; bu, curl’ün şifre sormasını sağlar ve böylece şifreniz kabuk geçmişinizde kalmaz. Kılavuzda, "çalıştığı sistemlerde curl, verilen seçenek argümanını işlem listelerinden gizler" denilmekle birlikte, "bu, kimlik bilgilerini korumak için yeterli değildir" ifadesi de eklenmiştir.
Oturum tabanlı bir API için çerezleri yakalayın ve yeniden kullanın:
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
Çalışmayan Bir POST İsteğinin Hata Ayıklaması
Neredeyse her sorunu çözen kısa bir adım dizisi.
Gönderdiğiniz içeriği tam olarak inceleyin:
curl -v --json '{"a":1}' https://api.example.com/items 2>&1 | grep -E '^[<>]'
>
ile başlayan satırlar isteğinizdir, <
ise yanıtıdır. Yöntemin, Content-Type
adresinin ve istek gövdesinin istediğiniz gibi olup olmadığını kontrol edin. “API çalışmıyor” bildirimlerinin şaşırtıcı bir kısmı bu aşamada çözülür.
Durum kodunu ve hata gövdesini okuyun:
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
Yaygın hataları yorumlayın:
| Durum | Genellikle şu anlama gelir |
|---|---|
| 400 | Gövde biçimi hatalı veya gerekli alan eksik |
| 401 | Kimlik bilgileri eksik veya geçersiz |
| 403 | Kimlik doğrulaması yapıldı ancak izin verilmedi |
| 405 | Uç nokta POST kabul etmiyor — URL'yi ve yöntemi kontrol edin |
| 413 | Gövde çok büyük |
| 415 | Yanlış Content-Type |
— klasik -d | |
| ile JSON hatası | |
| 422 | İçerik türü doğru, veriler doğrulamayı geçemedi |
415 ile 422 arasındaki farkı iyice kavramak önemlidir: 415, sarmalayıcının yanlış olduğunu, 422 ise içeriğin yanlış olduğunu gösterir. Bu konuyu 415 durum kodu nedir başlıklı yazımızda ayrıntılı olarak ele aldık.
Komut dosyalarında hataları belirgin bir şekilde gösterin:
curl --fail-with-body --silent --show-error \
--connect-timeout 5 --max-time 30 \
--json @payload.json https://api.example.com/items
--fail-with-body
, HTTP hatalarında sıfırdan farklı bir çıkış kodu verirken yanıt gövdesini de yazdırır; API, yararlı JSON hata mesajları döndürdüğünde istediğiniz de budur. Düz --fail
ise gövdeyi atar ve böylece açıklama da kaybolur.
Tarayıcı İsteğini curl'e Dönüştürme
Tarayıcıda çalışan ancak kodunuzda çalışmayan bir POST isteğini yeniden oluşturmanın en hızlı yolu — ve çoğu kişinin olması gerekenden çok daha geç keşfettiği bir teknik.
Geliştirici araçlarından kopyalayın. Chrome, Firefox ve Safari’de Ağ sekmesini açın, isteği bulun, sağ tıklayın ve “cURL olarak kopyala”yı seçin. Tarayıcının gönderdiği tüm başlıklar, çerezler ve gövdeyi içeren eksiksiz bir komut elde edersiniz. Bunu terminale yapıştırdığınızda aynı şekilde çalışması gerekir.
Bu, çoğu hata ayıklama oturumunun altında yatan soruyu hemen cevaplar: sorun istekte mi, yoksa kodumda mı? Kopyalanan komut çalışıyorsa ve sizinki çalışmıyorsa, fark gönderdiğiniz verilerde yatıyor demektir ve artık karşılaştırmak için her iki sürümü de yan yana elinizde tutuyorsunuz.
Ardından komutu sadeleştirin. Kopyalanan bir komut genellikle otuz başlık içerir ve bunların çoğu konuyla ilgisizdir. Bunları birkaçar birkaçar kaldırın ve hata verene kadar komutu yeniden çalıştırın. Geriye kalan, sunucunun gerçekten ihtiyaç duyduğu minimum kümedir ve işte bu, uygulamanıza ait olan kısımdır:
curl 'https://api.example.com/items' \
-H 'content-type: application/json' \
-H 'authorization: Bearer eyJhbG...' \
--data-raw '{"name":"Ada"}'
Tarayıcıların -d yerine --data-raw adresini gönderdiğini unutmayın; bunun nedeni, @ ile başlayan bir gövdenin aksi takdirde dosya adı olarak yanlış okunmasıdır.
Kopyalama işleminden sonra kaybolacak iki şeye dikkat edin. Çerezler, sabit bir başlık olarak eklenir ve süresi dolar. Ayrıca, sayfanın JavaScript ile hesapladığı her şey — bir CSRF belirteci, bir imza, zaman damgasından türetilen bir değer — kopyalanan komuta sabit bir dize olarak eklenir; bu nedenle bir kez çalışır ve sonra durur. Yeniden oluşturulan bir istek ilk seferde başarılı olup ikinci seferde başarısız olursa, bunun nedeni neredeyse her zaman budur ve çözüm, belirteci sabit kodlamak yerine onu almak olacaktır.
Ters yönde ise, birçok araç bir curl komutunu çoğu dil için koda dönüştürür; bu, başlıkları elle yeniden yazmaya gerek kalmadan çalışan bir komuttan çalışan bir istemciye geçmek için makul bir yoldur.
Proxy Üzerinden POST İşlemi
Kısa bir açıklama; burada önemli olan nokta bir teknikten ziyade bir uyarıdır.
curl -x http://user:pass@proxy.example.com:9000 \
--json '{"a":1}' https://api.example.com/items
İşleyiş değişmemiştir. Değişen şey, yeniden deneme hesaplamasıdır ve bu, --retry
eklemeden önce üzerinde düşünmeye değer kısımdır.
POST genellikle idempotent değildir. İki kez göndermek iki kayıt oluşturabilir. curl'ün --retry
komutu varsayılan olarak yalnızca geçici durumlarda tetiklenir, ancak --retry-all-errors
bunu önemli ölçüde genişletir — ve bir proxy üzerinden 5xx kodu genellikle hedefin geçici bir sorun yaşadığı değil, sizi reddettiği anlamına gelir. Bunu yeniden denemek en iyi ihtimalle anlamsızdır, en kötü ihtimalle ise bir yazma işleminin yinelenmesine neden olur.
Zaman aşımı, başarısızlığın kanıtı değildir. Sunucu bir isteği aldıktan sonra zaman aşımı olursa, siz bir hata mesajı görürken işlem tamamlanmış olabilir. Proxy üzerinden bağlanıldığında, bunun gerçekleşebileceği ek bir ara nokta vardır. İşlem önemliyse, güvenli olmak için yeniden deneme mantığına güvenmek yerine bir idempotency anahtarı kullanın — çoğu ciddi API bunu destekler.
Ve hangi adımda reddedildiğinizi kontrol edin. %{http_connect}
, proxy'nin CONNECT isteğine verdiği yanıtı, hedefin durumundan ayrı olarak bildirir:
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
, proxy'nin kimlik bilgilerini istediği anlamına gelir. connect=200 status=403
, proxy'nin çalıştığı ancak hedefin reddettiği anlamına gelir. Farklı sorunlar, farklı çözümler.
Sık Sorulan Sorular
curl ile POST isteği nasıl gönderilir?
curl -d "key=value" URL. -d seçeneği POST'u ima eder, bu nedenle -X POST gereksizdir. Ayrıca Content-Type: application/x-www-form-urlencoded değerini de ayarlar; bu, form gönderimleri için doğrudur ancak JSON için yanlıştır.
curl ile JSON'u POST olarak nasıl gönderirim?
curl --json '{"key":"value"}' URL kısayoludur — bu, --data-binary değerini ayarlamanın yanı sıra hem Content-Type hem de Accept başlıklarını application/json olarak ayarlar. Daha uzun biçim ise -X POST -H "Content-Type: application/json" -d '...' şeklindedir. --json komutunun JSON'unuzu doğrulamadığını unutmayın.
Neden curl'dan 415 Unsupported Media Type hatası alıyorum?
Neredeyse her zaman, içerik türünü ayarlamadan -d komutunu JSON gövdesi ile kullandığınız içindir. -d komutu form kodlu veri gönderir ve JSON bekleyen bir API bunu reddeder. --json komutunu kullanın veya -H "Content-Type: application/json" ekleyin.
-d ile --data-raw arasındaki fark nedir?
-d, başındaki @ ifadesini "bu dosyadan oku" olarak yorumlar. --data-raw ise bunu yapmaz; dolayısıyla, verileriniz @ ile başlıyorsa (örneğin bir e-posta adresi veya bir kullanıcı adı), ihtiyacınız olan seçenek budur. Bunun dışında ikisi de aynı şekilde çalışır.
curl POST ile bir dosyayı nasıl yüklerim?
curl -F "file=@document.pdf" URL, multipart/form-data komutunu gönderir. Dosyayı ek olarak eklemek için @ komutunu, içeriğini metin alanı değeri olarak göndermek için < komutunu kullanın. Content-Type başlığını kendiniz ayarlamayın — curl, gerekli sınırla birlikte bunu oluşturur.
Bir dosyadan POST verilerini nasıl gönderirim?
JSON için curl --json @payload.json URL, satır sonları dahil tam baytlar için --data-binary @file kullanın. Boşlukların önemli olduğu durumlarda -d @file kullanmaktan kaçının, çünkü -d satır sonlarını ve satır başı karakterlerini kaldırır.
Ampersand içeren bir değeri nasıl POST yapabilirim?
--data-urlencode "field=value with & inside" adresini kullanın. Düz -d adresinde, ampersand bir alan ayırıcısı olarak okunur ve değeriniz o noktada sessizce kesilir.
Başarısız bir POST isteğini yeniden denemeli miyim?
Dikkatli olun. POST genellikle idempotent değildir, bu nedenle yeniden deneme bir yinelenmeye neden olabilir — ayrıca zaman aşımı, sunucunun isteği işleme koymadığını kanıtlamaz. API destekliyorsa bir idempotency anahtarı kullanın ve --retry-all-errors ile dikkatli olun; özellikle de 5xx kodunun geçici bir hata yerine genellikle reddedilme anlamına geldiği bir proxy üzerinden.
Sonuç
Konunun tamamı tek bir soruya indirgenebilir: Uç nokta hangi içerik türünü istiyor ve komutunuz bunu gönderiyor mu?
-d form-encoded gönderir; bu, form gönderimleri için doğrudur ancak JSON için yanlıştır — ve insanların karşılaştığı çoğu 415 hatasının arkasında bu tek uyumsuzluk yatmaktadır. Bunun yerine tercih edilmesi gereken seçenek --json'dir ve bu seçenek yeterince bilinmemektedir: gövde işlemeyi ve her iki başlığı da ayarlayan tek bir bayrak olup, dosyalar ve stdin için @ desteği sunar.
Bunun ötesinde, hatırlamaya değer belirli nedenlerle farklı seçenekler de mevcuttur. Verileriniz @ ile başlıyorsa --data-raw kullanın. Satır sonlarının önemli olduğu durumlarda --data-binary kullanın. Bir değer, form kodlamasını bozacak karakterler içeriyorsa --data-urlencode kullanın. Gerçek dosya yüklemeleri için -F kullanın; bir dosyayı eklemek için @ ve bir dosyadan metin alanını okumak için < kullanın.
Bir şey yolunda gitmediğinde, -v ile çalıştırın ve herhangi bir değişiklik yapmadan önce > satırlarını okuyun. Gönderdiğiniz istek, genellikle gönderdiğinizi sandığınız istek değildir ve bu alandaki karışıklıkların çoğu bu farktan kaynaklanır.
