2016-01-03 17 views
7

Es wird entweder nicht gesendet oder nicht richtig empfangen. Die Verwendung von curl direkt von der Befehlszeile (mit der Option -d) oder von PHP (mit CURLOPT_POSTFIELDS) funktioniert.Guzzle sendet PSR-7 POST Body nicht korrekt

I beginnen mit einem PSR-7-Anfrage:

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

I Authentication Header hinzufügen, die korrekt gegen die API authentifiziert:

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

Dann fügen I die Anfrage Körper:

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

Ich kann die Nachricht an die API senden:

Die Antwort, die ich zurück erhalte, zeigt an, dass der Parameter "args" von der API einfach nicht gesehen wurde. Ich habe versucht, die Authentifizierungs-Token an die args bewegen:

'args=dot&access_token=123456789' 

Diese funktionieren soll, und tut Arbeit mit Curl von der Kommandozeile (-d access_token=123456789), aber die API nicht auch diese Parameter, um zu sehen, wenn das Senden cia curl (6.x) wie oben.

ich die Meldung sehen nicht den Körper enthalten:

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

Also, was hier schief gehen könnte? Werden die Parameter nicht gesendet oder werden sie im falschen Format gesendet (möglicherweise wird '=' codiert?) Oder wird möglicherweise der falsche Inhaltstyp verwendet? Es ist schwierig zu sehen, was "auf dem Draht" gesendet wird, wenn Guzzle verwendet wird, da die HTTP-Nachricht formatiert und viele Ebenen tief gesendet wird.

Edit: eine local test script anstelle der Remote-API aufrufen, erhalte ich diese rohe Nachricht Detail:

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 

So sieht es aus wie der Körper ist gesendet werden, also denke ich, etwas anderes zu fehlen Informieren Sie die Remote-API, wie dieser Körper zu interpretieren ist.

Edit: die Befehlszeilen curl, das funktioniert, auf den gleichen Testskript gesendet werden, gibt mir zwei zusätzliche Header-Felder in der Anfrage:

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

ich es erraten, werde die Content- Type Header, der in der Guzzle-Anfrage fehlt, die die Ursache des Problems ist. Ist das also ein Guzzle Bug? Sollte es nicht immer einen Inhaltstyp senden, basierend auf den Annahmen, die es macht, die listed in the documentation sind?

Antwort

6

Die GuzzleHttp\Client bietet alle notwendigen Verpackung. verfügbar

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

Dokumentation Guzzle Request Options

Edit: Allerdings, wenn Ihre Anfragen dann innerhalb GuzzleHttp \ Pool verwendet werden, können Sie einfach alles in die folgenden:

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

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

So ist die Guzzle * Client * wird die richtigen 'Content-Type'-Header einfügen, vorausgesetzt, Sie geben ihm die Rohdaten auf die richtige Weise (' form_params' ist der Auslöser hier, denke ich). Guzzle * fügt * keine Header hinzu, ohne sie beim Erstellen einer PSR-7-Request-Nachricht explizit anzugeben. Mein Ziel war es, eine PSR-7-Nachricht zu erstellen, die über jeden HTTP-Client gesendet werden kann, der PSR-7-Nachrichten unterstützt, und zwar so einfach wie möglich, so dass nur PSR verwendet werden kann -7 Methoden auf dem Helfer Guzzle/PSR-7-Paket. – Jason

+0

Es sollte wahrscheinlich ein Leerzeichen nach 'Bearer' in den Anführungszeichen stehen. – Jason

+0

Korrekt, der Client fügt bei Verwendung der Anforderungsoptionen 'auth' und 'form_params' automatisch die richtige Kopfzeile für den Inhaltstyp und den Authentifizierungsheader ein. Sie müssen sich daran erinnern, wenn Sie die Anfragen für die Verwendung mit anderen PSR7-kompatiblen Paketen manuell erstellen. –

9

Die Content-Type Header war das Problem. Normalerweise wird Guzzle Ihre Hand halten und Header einfügen, die es für notwendig erachtet, und macht eine gute Schätzung für die Content-Type basierend auf dem, was Sie ihm gegeben haben, und wie Sie es gegeben haben.

Mit Guzzle PSR-7-Nachrichten wird nichts von dieser Hand gehalten. Es lässt streng alle Header für Sie zu behandeln.Also, wenn POST-Parameter zu einem PSR-7 Request hinzufügen, müssen Sie explizit den Content-Type gesetzt:

$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'); 

Die Fähigkeit, in dem params als Array zu übergeben und den Rest zu arbeiten, zu verlassen Guzzle, nicht Anwendung auf Guzzles PSR-7-Implementierung. Es ist ein wenig ungeschickt, da Sie die POST-Parameter in eine HTTP-Abfragezeichenfolge serialisieren und dann in einen Stream stecken müssen, aber da haben Sie es. Es gibt möglicherweise einen einfacheren Weg, dies zu handhaben (z. B. eine Wrapperklasse, die mir nicht bekannt ist), und ich warte ab und sehe, ob etwas auftaucht, bevor ich diese Antwort akzeptiere.

bewusst sein, dass eine multipart/form-data-Request-Nachricht, wenn die Konstruktion, müssen Sie die Grenze Zeichenfolge an den Content-Type hinzuzufügen:

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

Wo $boundary kann der mehrteiliger Körper in Konstruktion so etwas wie uniq() und sein .