javascript - Miksi CURLin PUT epäonnistuu todennuksessa ennen kuin se lataa datan, mutta XHR PUT vasta sen jälkeen?
Työskentelen REST-rajapinnan kanssa, jossa käytetään token-pohjaista autentikointia, ja joillakin käyttäjillä on oikeudet ladata tiedosto ja joillakin ei.
Ongelmana on, että kun jotkut käyttäjät, joilla ei ole lupaa tiedoston lataamiseen, yrittävät ladata tiedoston (sanotaan 1 Gt tiedoston), saan virhevastauksen vasta sen jälkeen, kun koko 1 Gt on ladattu.
Jos kopioin pyynnön curlina Chrome-kehittäjätyökaluista ja lähetän sen terminaalin kautta, se epäonnistuu heti.
Testasin curl-komentoa käyttäjän tokenilla, jolla on oikeudet ladata, se toimii odotetusti.
Joten, miten curl eroaa XHR:stä?
Curl on synkroninen, ja XHR ei ole oletuksena. Yritin tehdä XHR:stä synkronisen, mutta sen on silti ladattava koko tiedosto ennen kuin se sai vastauksen.
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);
}
Tässä on tarkka curl-komento, muotoiltu luettavuutta varten:
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
//Otsikot poistettu paitsi token
curl 'https://my-website.com/54321/my-filename.jpg'
-X PUT
-H 'X-Auth-Token: fsadsdsdaf'
-F "data=@/Users/satish/abc.jpg"
--compressed --insecure
--- Päivitys 21-02-2017 ---
Sulkeakseni pois minkä tahansa API-päätepistekohtaisen käyttäytymisen, kirjoitin karkeaa PHP-skriptiä testatakseni tätä havaintoa, ja se on edelleen totta. Alla on PHP-skripti, jonka yritin ladata.
<?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 );
?>
Vastaus #1
Kun curl tekee PUT-pyynnön, joka vaatii todennuksen, se lähettää ensin "kokeilupyynnön" ilman sisältöä, jotta palvelimella on mahdollisuus hylätä yhteys ennen kuin mitään dataa lähetetään.
Tätä ei näytä olevan dokumentoitu missään muualla kuin koodikommentissa kohdassa Curl_http() tiedostossa lib/http.c.
(Huomaa, että curlin versioissa ennen 7.53.0 (2017‑02‑22, eli uudempi kuin kysymys), oli virhe, jossa käyttäjän antama Content‑Length -otsikko (tai ei otsikkoa) lähetettiin Content‑Length: 0 sijasta.)
XHR ei toteuta tällaista tutkintaa, vaan lähettää kaiken sisällön heti alkuperäisen pyynnön mukana.
Vastaus #2
Kokeile lisätä -H "Expect:" curl-komentoosi.
Voin olla väärässä, mutta tässä on aavistukseni:
- XHR: Expect on kielletty otsikon nimi
- curl: lisää oletuksena
Expect: 100-continue