Weboldal keresés

javascript - Miért bukik el a CURL PUT-ja a hitelesítésnél a teher felküldése előtt, míg az XHR PUT csak utána?


Egy REST API-val dolgozom token alapú hitelesítéssel, ahol egyes felhasználóknak van jogosultságuk fájl feltöltésére, míg másoknak nincs.

A probléma az, amikor egy felhasználó, akinek nincs engedélye fájl feltöltésére, megpróbál feltölteni (mondjuk egy 1 GB-os fájlt), a hibaválaszt csak azután kapom, hogy az egész 1 GB fel lett töltve.

Ha a kérést a Chrome fejlesztői eszközeiből curl-ként másolom és a terminálon keresztül küldöm, az azonnal sikertelen.

Leteszteltem a curl parancsot egy olyan felhasználó tokenjével, akinek van jogosultsága feltöltésre, és a várt módon működik.

Szóval, miben különbözik a curl az XHR-től?

A Curl szinkron, az XHR alapértelmezés szerint nem. Megpróbáltam szinkronná tenni az XHR-t, de még mindig fel kell töltenie az egész fájlt, mielőtt választ kapna.

function upload(file, url) {
    var xhr = new XMLHttpRequest();
    xhr.upload.key = xhr.key = file.key
    xhr.upload.addEventListener("progress", updateProgress);
    xhr.addEventListener("error", transferFailed);
    xhr.addEventListener("abort", transferCanceled);
    xhr.open("PUT", url);
    xhr.setRequestHeader("Content-Type", "application/octet-stream");
    xhr.setRequestHeader("X-Auth-Token", service.token.token);


    xhr.addEventListener("readystatechange", function (e) {
      if (this.readyState === 4 && this.status >= 200 && this.status < 300) {
        transferComplete(e)
      }
      if (this.readyState === 4 && this.status === 0) {
        transferFailed(e)
      }
      if (this.status >= 400) {
        transferFailed(e)
      }

    });


    xhr.send(file);
}

Itt van a pontos curl parancs, olvashatóság érdekében formázva:

curl 'https://my-website.com/54321/my-filename.jpg' 
  -X PUT   
  -H 'Pragma: no-cache' 
  -H 'Origin: https://my-website.com' 
  -H 'Accept-Encoding: gzip, deflate, sdch, br' 
  -H 'Accept-Language: en-US,en;q=0.8' 
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' 
  -H 'Content-Type: application/octet-stream' 
  -H 'Accept: */*' 
  -H 'Cache-Control: no-cache' 
  -H 'X-Auth-Token: fsadgsdgs' 
  -H 'Referer: https://some-allowed-origin-referrer.com/' 
  -H 'Connection: keep-alive' 
  -H 'Content-Length: 86815' 
  -F "data=@/Users/satish/abc.jpg" --compressed --insecure 

//Fejlécek eltávolítva a token kivételével

  curl 'https://my-website.com/54321/my-filename.jpg' 
    -X PUT  
    -H 'X-Auth-Token: fsadsdsdaf' 
    -F "data=@/Users/satish/abc.jpg" 
    --compressed --insecure 

--- Frissítés 2017-02-21 ---

Annak kizárása érdekében, hogy bármilyen API végpont-specifikus viselkedésről van szó, írtam egy nyers PHP szkriptet ennek a megfigyelésnek a tesztelésére, és ez még mindig igaz. Lentebb látható a PHP szkript, amelyet feltöltésre próbáltam.

<?php
/**
 * If I comment out the below lines, then curl is failing immediately.
 * But XHR doesn't
 **/

// http_response_code(400);
// return;

/* PUT data comes in on the stdin stream */
$putdata = fopen( "php://input", "r" );

/* Open a file for writing */
$file = fopen( "/Users/satish/Work/Development/htdocs/put-test/wow.jpg", "w" );

/* Read the data 1 KB at a time
   and write to the file */
while ( $data = fread( $putdata, 1024 ) ) {
    fwrite( $file, $data );
}

/* Close the streams */
fclose( $file );
fclose( $putdata );
?>

Válasz #1

Amikor a curl PUT kérést küld hitelesítés szükségessége mellett, először egy tartalom nélküli „felderítő” kérést küld, hogy a szervernek lehetősége legyen megtagadni a kapcsolatot, mielőtt bármilyen adat elküldésre kerülne.

Úgy tűnik, hogy ez sehol sem dokumentált, kivéve egy megjegyzést a Curl_http() kódban a lib/http.c fájlban.

(Vegye figyelembe, hogy a curl 7.53.0 előtti verzióiban (2017‑02‑22, azaz az adott kérdésnél újabbak) volt egy hiba, amely során a felhasználó által megadott Content‑Length fejléc (vagy ha nem volt fejléc) lett elküldve a Content‑Length: 0 helyett.)

Az XHR nem valósít meg ilyen próbát, és egyszerűen elküldi az összes tartalmat a kezdeti kéréssel.

Válasz #2

Próbáld meg hozzáadni a -H "Expect:" opciót a curl parancshoz.

Lehet, hogy tévedek, de itt van a megérzésem:

  • XHR: Az Expect tiltott fejlécnév
  • curl: alapértelmezés szerint hozzáadja a Expect: 100-continue kódot