Как добавить HTTP заголовки к SOAP запросу?
Из PHP-сценария я отправляю SOAP-запрос. Помимо данных в теле запроса сервер ожидает от меня еще два HTTP-заголовка. Не могу понять, как правильно их ему отправить.
$oSoapClient = new SoapClient( $url, $aOptions ); $aHeaders = array(); $aHeaders[] = new SoapHeader( 'http://soapinterop.org/echoheader/', 'token', $token ); $aHeaders[] = new SoapHeader( 'http://soapinterop.org/echoheader/', 'user-token', $user_id ); $oSoapClient->__setSoapHeaders( $aHeaders ); $result = $oSoapClient->__doRequest( $sXml, $url, null, SOAP_1_1 );
И сервер возвращает ошибку с сообщением о том, что требуемые ему заголовки не найдены.
Из документации к SOAP на php.net ничего нового для себя не нашел.
Простой 2 комментария
AUser0, в документации на php.net сказано, что этот метод является устаревшим.
К тому же, мне не удаётся сформировать данные в виде массива или объекта, которые бы соответствовали WSDL на стороне сервера. Как, например, для таких данных пространства имён задавать?
__setSoapHeaders устанавливает заголовки soap запроса, а не http. Они размещаются в элементе Header. По вашему примеру кода получится что-то типа такого:
Для добавления именно http заголовков нужно создать stream context:
$aOptions['stream_context'] = stream_context_create([ 'http' => [ 'header' => "token: abc\r\nuser-token: 123" ] ]); $oSoapClient = new SoapClient( $url, $aOptions ); $result = $oSoapClient->__doRequest( $sXml, $url, null, SOAP_1_1 );
Благодарю вас за подсказку. Я тоже уже пришел к пониманию того, что пытался таким образом передать заголовки тела SOAP-запроса, а не HTTP-заголовки. И тоже сейчас вожусь с функцией stream_context_create().
Мне сейчас сервер отвечает: Доступ к сервису для token запрещен. И сейчас для меня загадка в этом.
«token» здесь, вероятно, это имеется в виду имя http-заголовка, который я передаю, а не само значение token. И почему оно приводит к ошибке, я не могу понять, так как имя заголовка я беру из руководства для подключения к API.
Заголовки должны выглядеть так: FNS-OpenApi-Token и FNS-OpenApi-UserToken.
Второй должен быть представлен в виде закодированной в base64 строки. Сейчас мой код выглядит так.
$options[ 'stream_context' ] = stream_context_create([ 'http' => array( 'header' => "FNS-OpenApi-token: " . $token . "\r\nFNS-OpenApi-UserToken: " . $userToken ) ]);
Ну и в ответ на это я получаю сообщение о запрете доступа для token.
Вызов метода $oSoapClient->__getLastRequestHeaders() показывает такие заголовки:
POST /open-api/ais3/KktService/0.1 HTTP/1.1 Host: openapi.nalog.ru:8090 Connection: Keep-Alive User-Agent: PHP-SOAP/7.2.24-0ubuntu0.18.04.2 Content-Type: text/xml; charset=utf-8 SOAPAction: "urn:SendMessageRequest" Content-Length: 1520 FNS-OpenApi-token: d23597c6486f4b53b873eed030dae3fb FNS-OpenApi-UserToken: 0K3RgtC+INC30LDQutC+0LTQuNGA0L7QstCw0L3QvdCw0Y8g0YHRgtGA0L7QutCw
То есть заголовки переданы, но не приняты, почему-то.
Раз запрос технически соответствует документации, значит проблема административная и решить её можно только запросом в техподдержку. Спросите у них почему с вашим токеном запросы отклоняются.
Vamp, благодарю вас за советы. Разобрался со всем, исправил у себя все ошибки, работает.
Теперь передо мной иная задача. Используя JavaScript получить доступ к камере смартфона, чтобы считать QR-код, и обработать информацию из него. Но это уже другая тема )
Класс SoapHeader
None of the examples really do it for me.
Note: you should NOT need to hard-code any XML.
Here is an example of creating a nested header and including a parameter.
$client = new SoapClient(WSDL,array());
$auth = array(
‘UserName’=>’USERNAME’,
‘Password’=>’PASSWORD’,
‘SystemId’=> array(‘_’=>’DATA’,’Param’=>’PARAM’),
);
$header = new SoapHeader(‘NAMESPACE’,’Auth’,$auth,false);
$client->__setSoapHeaders($header);
Gives the following header XML:
If you want to create an soap header wihtout namespace and without an item key value setup, you can use SoapVar
you can use this php code:
$headerVar = new SoapVar ( ‘
XSD_ANYXML );
$header = new SoapHeader ( ‘http://tempuri.org/’ , ‘RequestParams’ ,
$headerVar );
?>
Just to add some note regarding his john at jtresponse dot co dot uk
In PHP you can try following code to avoid the
$Auth = new stdClass();
$Auth->SystemId = «DATA»;
$Auth->UserName = «USERNAME»;
$Auth->Password = «PASSWORD»;
$header = new SoapHeader(‘NAMESPACE’,’Auth’,$Auth,false);
$soapClient->__setSoapHeaders($header);
Something I came across that I feel should be noted here is if you come across the error «cannot be processed at the receiver, due to an addressfilter mismatch at the endpointdispatcher. check that the sender and receiver’s endpointaddresses agree.» and you are absolutely sure your protocols and the service URL matches, send ‘To’ SoapHeader.
$soapHeaders = array(
new \SoapHeader(‘http://www.w3.org/2005/08/addressing’, ‘Action’, ‘your-action’, true),
new \SoapHeader(‘http://www.w3.org/2005/08/addressing’, ‘To’, ‘your-service-endpoint-url’)
);
$soapClient->__setSoapHeaders($soapHeaders);
Example by john at jtresponse dot co dot uk does miss one important point: to be able to add attributes they must be mentioned in WSDL. If they not exist in WSDL they WILL NOT appear as attributes but rather