2016-01-03 11 views
7

Non viene inviato o non viene ricevuto correttamente. L'utilizzo di curl direttamente dalla riga di comando (utilizzando l'opzione -d) o da PHP (utilizzando CURLOPT_POSTFIELDS) funziona.Guzzle che non invia correttamente il corpo POST PSR-7

cominciare con la richiesta PSR-7:

$request = GuzzleHttp\Psr7\Request('POST', $url); 

aggiungo header di autenticazione che autentica contro l'API correttamente:

$request = $request->withHeader('Authorization', 'Bearer ' . $accessToken); 

poi aggiungo corpo della richiesta:

// The parameter for the API function 
$body = \GuzzleHttp\Psr7\stream_for('args=dot'); 
$request = $request->withBody($body); 

Posso inviare il messaggio all'API:

$client = new \GuzzleHttp\Client(); 
$response = $client->send($request, ['timeout' => 2]); 

La risposta che ottengo indica che il parametro "args" semplicemente non è stato visto dall'API. Ho cercato di spostare il token di autenticazione per i args:

'args=dot&access_token=123456789' 

Questo dovrebbe funzionare, e fa lavoro con l'arricciatura dalla riga di comando (-d access_token=123456789), ma l'API non riesce a vedere che il parametro anche durante l'invio di cia ricciolo (6.x) come sopra.

posso vedere il messaggio non contiene il corpo:

var_dump((string)$request->getBody()); 
// string(8) "args=dot" 
// The "=" is NOT URL-encoded in any way. 

Allora, cosa potrebbe andare male qui? I parametri non vengono inviati o vengono inviati nel formato sbagliato (forse '=' è in corso la codifica?), Oppure è forse usato il tipo di contenuto sbagliato? È difficile vedere cosa viene inviato "sul filo" quando si utilizza Guzzle, dal momento che il messaggio HTTP è formattato e inviato molti livelli di profondità.

Edit: Richiamo di un local test script invece di API a distanza, ottengo questo messaggio particolare grezzo:

POST 
CONNECTION: close 
CONTENT-LENGTH: 62 
HOST: acadweb.co.uk 
USER-AGENT: GuzzleHttp/6.1.1 curl/7.19.7 PHP/5.5.9 

args=dot&access_token=5e09d638965288937dfa0ca36366c9f8a44d4f3e 

Quindi sembra che il corpo è di essere inviato, quindi credo che qualcosa manca a dì all'API remota come interpretare quel corpo.

Edit: il ricciolo riga di comando che funziona, ha inviato al medesimo script di test, mi dà due campi di intestazione supplementari nella richiesta:

CONTENT-TYPE: application/x-www-form-urlencoded 
ACCEPT: */* 

ho intenzione di indovinare è il Content digita l'intestazione che manca nella richiesta Guzzle che è la fonte del problema. Quindi questo è un bug di Guzzle? Non dovrebbe sempre inviare un Content-Type, in base alle ipotesi che sono listed in the documentation?

risposta

6

Il GuzzleHttp\Client fornisce tutto il necessario avvolgimento.

$response = $client->post(
    $uri, 
    [ 
     'auth' => [null, 'Bearer ' . $token], 
     'form_params' => $parameters, 
]); 

Documentazione disponibile Guzzle Request Options

Modifica: Tuttavia, se le richieste vengono utilizzati all'interno di GuzzleHttp \ Pool allora, si può semplicemente tutto in quanto segue:

$request = new GuzzleHttp\Psr7\Request(
    'POST', 
    $uri, 
    [ 
     'Authorization' => 'Bearer ' . $token, 
     'Content-Type' => 'application/x-www-form-urlencoded' 

    ], 
    http_build_query($form_params, null, '&') 
); 
+0

Così il cliente Guzzle * * inserirà le intestazioni di 'Content-Type' corrette, a patto che le forniate i dati grezzi nel modo giusto (' form_params' è il trigger qui, immagino). Guzzle * non * aggiungerà le intestazioni senza che le vengano fornite esplicitamente durante la costruzione di un messaggio di richiesta PSR-7. Il mio scopo qui era di costruire un messaggio PSR-7 che potesse essere inviato attraverso qualsiasi client HTTP che supporta i messaggi PSR-7, tanto per la purezza di vedere solo che può essere fatto nel modo più portabile possibile, quindi usando solo il PSR -7 metodi sul pacchetto helper Guzzle/PSR-7. – Jason

+0

Probabilmente ci dovrebbe essere uno spazio dopo 'Bearer', tra virgolette. – Jason

+0

Corretto, il client inserirà automaticamente l'intestazione content-type appropriata e l'intestazione di autenticazione quando si utilizzano le opzioni di richiesta 'auth' e 'form_params'. È qualcosa che bisogna ricordare quando si costruiscono manualmente le richieste di utilizzo con altri pacchetti conformi a PSR7. –

9

L'intestazione Content-Type era il problema. Normalmente, Guzzle terrà la tua mano e inserirà le intestazioni che ritiene necessarie, e fa una buona ipotesi sul Content-Type in base a ciò che gli hai dato, e come lo hai dato.

Con i messaggi PSR-7 di Guzzle, non è stato eseguito alcun tipo di presa manuale. Lascia rigorosamente tutte le intestazioni da gestire.Così, quando l'aggiunta di parametri POST ad un PSR-7 Request, è necessario impostare in modo esplicito il Content-Type:

$params = ['Foo' => 'Bar']; 
$body = new \GuzzleHttp\Psr7\stream_for(http_build_query($params)); 
$request = $request->withBody($body); 
$request = $request->withHeader('Content-Type', 'application/x-www-form-urlencoded'); 

La capacità di passare nelle params come un array e di lasciare gozzovigliare a lavorare fuori il resto, non si applicano all'implementazione PSR-7 di Guzzle. È un po 'maldestro, in quanto è necessario serializzare i parametri POST in una stringa di query HTTP e quindi inserirli in uno stream, ma ce l'hai. Potrebbe esserci un modo più semplice per gestirlo (ad esempio una classe wrapper di cui non sono a conoscenza), e aspetterò e vedere se ne viene fuori prima di accettare questa risposta.

Siate consapevoli anche che se la costruzione di un messaggio multipart/form-data richiesta, è necessario aggiungere la stringa confine per il Content-Type:

$request = $request->withHeader('Content-Type', 'multipart/form-data; boundary=' . $boundary); 

Dove $boundary può essere qualcosa come uniq() ed è utilizzato nella costruzione del corpo multipart .

Problemi correlati