Problema respuesta de API REST

Hola,

Acudo al foro para consultar y pedir asesoramiento sobre API REST en Mapuche.

En la UNSAM hemos implementado un cliente desarrollado en angular y PHP para ver y descargar los recibos de sueldos.

La consulta de los recibos la realizamos mediante API con sockets del lado de PHP.
El problema que estamos teniendo es que Mapuche nos está devolviendo dentro del body una cadena “aleatoria” justo antes de comenzar el json.

La URI de consulta: /agentes/{legajo}/recibos



102f0
[
    {
        "liquidacion": 744,
        "per_liano": 2012,
        "per_limes": 3,
        "desc_liqui": "Marzo 2012",
        "fecha_emision": "2012-04-03",
        "fecha_ultap": "2012-03-09",
        "per_anoap": 2012,
        "per_mesap": 2,
        "desc_lugap": "AFIP Agencia Nº 15",
        "plantilla": null,

Lo curioso, dentro de Swagger UI , al hacer la misma consulta no devuelve esa cadena. Pero al hacerla por socket, sí.
Otro detalle, no devuelve siempre la cadena esa ni es igual para todos los legajos.

El código que resuelve la petición es:

	function get_list($legajo)
	{
		$recibos = rest_recibos_nucleo::get_list($legajo);
		rest::response()->get_list($recibos);
	}

¿Alguna sugerencia o explicación de cómo evitar que devuelva esa cadena dentro del body de response?

Muchas gracias,
Mariana

Hola Mariana,

estuve haciendo unas pruebas y no pude tener el error que comentas.
Por lo que pude deducir es que tienen algo mal hecho en el cliente.
Una de las pruebas que hice fue crear un cliente e invocar el servicio rest que mencionas.

Revisen un poquito el cliente que seguro encuentran el problema por ese lado.

Saludos
Poli

Gracias por responder!

Entendemos que hay algo que debe estar faltando del lado Mapuche o del lado cliente.
Ya hemos revisado el cliente, hemos hecho consultas distintas y seguimos teniendo el mismo problema.

Otro detalle, que no he comentado en el post anterior es que no sucede con todos los clientes igual. No es que estamos trayendo mal los resultados, sino que desde Mapuche siempre nos devuelve una cadena aleatoria distinta y no es todos los usuarios/legajos.

¿Estará faltando alguna codificación, header desde el cliente a la API?

Gracias por la ayuda!

hay alguna posibilidad que me pases algún ejemplo del cliente por acá? para ver si puedo reproducir el problema ya que si no puedo reproducirlo (con los clientes que probé yo) no podría decirte mucho.
probaron otros servicios rest con el mismo cliente y les pasa lo mismo?

saludos

Gracias por contestar!

Nosotros tenemos un objeto HttpRequest.php que armamos nuestra consulta a la API:


<?php
namespace controllers;
/*
 *  simple HttpRequest example using PHP
 *  tom slankard
 */
class HttpRequest {
  public $url = null;
  public $method = 'GET';
  public $body = null;
  public $headers = Array();
  public $allow_redirect = true;
  private $url_info = null;
  private $host_name = null; 
  private $host_ip = null;
  public $response_body = null;
  private $response_headers = Array();
  private $response_code = null;
  private $response_message = null;
  private $port = null;
  private $verbose = true;
  private $flagLeerBody = false;

  public function __construct($url, $method = 'GET', $user = null, $pass = null) {
    $this->flagLeerBody = false;
    $this->url = $url;
    $this->method = $method;
    //  parse url
    $this->url_info = parse_url($url);

    $this->host_name = $this->url_info['host'];
    $this->host_ip = gethostbyname($this->host_name);

    //  get port number given the scheme
    if(!isset($this->url_info['port'])) {
      if($this->url_info['scheme'] == "http")
        $this->port = 80;
      else if($this->url_info['scheme'] == "https")
        $this->port = 443;
    } else {
      $this->port = $this->url_info['port'];
    }

    //  add default headers
    $this->headers["Host"] = "$this->host_name";
    $this->headers["Accept-Charset"] = "ISO-8859-1, utf-8;q=0.66, *;q=0.66";
    // $this->headers["Connection"] = "close";

    // Set Authorization if user is not null
    if(!is_null($user))
    {
      $encode = base64_encode($user.':'.$pass);
      $this->headers["Authorization"] = "Basic $encode";
    }

  }

  private function constructRequest() {
    $path = "/";
    if(isset($this->url_info['path']))
    {
      $path = $this->url_info['path'];

      /* Se agrega nueva funcionalidad para pasar querys a la url */
      if(isset($this->url_info['query']))
      {
        $path .= "?".$this->url_info['query'];
      }
    }

    $req = "$this->method $path HTTP/1.1\r\n";

    foreach($this->headers as $header => $value) {
      $req .= "$header: $value\r\n";
    }

    return "$req\r\n";
  }

  ///  reads a line from a file
  function readLine($fp)
  {
    $line = "";
    while (!feof($fp)) {
      // $fgetsLine = fgets($fp, 2048);
      $fgetsLine = fgets($fp, 128);
      // $fgetsLine = fgets($fp);

      /*
       No comprendo porque en el fgets antes del body encuentra un número "random" y rompe el json
       Si un número en la línea, lo elimina para no romper la estructura del json.
      */
      if(!is_numeric(trim($fgetsLine)))
      {
        $line .= $fgetsLine;
        
      }
      if (substr($line, -1) == "\n") {
        return trim($line, "\r\n");
      }
    }

    return $line;
  }


  public function send() {
    $fp = fsockopen($this->host_ip, $this->port, $errno, $errstr, 30);

    if (!$fp) {
      echo "$errstr ($errno)
\n";
    } else {
        

    //  construct request
    $request = $this->constructRequest();

    //  write request to socket
    // fwrite($fp, $request);
    fputs($fp, $request);

    if(!empty($this->body))
    {
      fputs($fp, $this->body);
    }


    //  read the status line
    $line = $this->readline($fp);
    $status = explode(" ", $line);

    //  make sure the HTTP version is valid
    if(!isset($status[0]) || !preg_match("/^HTTP\/\d+\.?\d*/", $status[0]))
      die("Couldn't get HTTP version from response.");
    //  get the response code
    if(!isset($status[1]))
      die("Couldn't get HTTP response code from response.");
    else $this->response_code = $status[1];
    
    //  get the reason, e.g. "not found"
    if(!isset($status[2]))
      die("Couldn't get HTTP response reason from response.");
    else $this->response_reason = $status[2];


    //  read the headers
    do {
      $line = $this->readLine($fp);
      if($line != "") { 
        $header = explode(":", $line);
        $this->response_headers[$header[0]] = ltrim($header[1]);
      }
    } while(!feof($fp) && $line != "");

    //  read the body

    $this->response_body = "\n";
    do {
      $line = $this->readLine($fp); {
        /*
        @TODO: Comprender y corregir por qué dentro del body de vuelve una cadena de 717d antes del comienzo del json
        */
        // var_dump($line);
        // var_dump($this->limpiarJSONToken($line));
        if($this->empiezaJson($line))
        {
          $this->flagLeerBody = true;
        }

        if($this->flagLeerBody)
        {
          if($line)
          {
            $this->response_body .= "$line\n";
          }
        }
      }
    } while(!feof($fp));

    //  close the connection
    fclose($fp);
    return TRUE;
    }
  }

  public function setBody($body) {
    $this->body = $body;
  }

  public function getResponseStatus() {
    return $this->response_code;
  }
  public function getHeaders() {
    return $this->response_headers;
  }
  public function getResponseBody() {
    return $this->response_body;
  }


  /* Funcion auxiliar, busca si es un [ */
  private function empiezaJson($string)
  {
    return strpos($string, "[") !== false || strpos($string, "{") !== false;
  }
}

?>

Luego creamos ese objeto pasandole la url a la API, el método (GET), usuario y contraseña.


       $req = new HttpRequest($url, $method, $usuario_rest, $pass_rest);
      $req->setBody($body);

      // $req->headers["Connection"] = "close";
      $req->headers["Cache-Control"] = "no-cache";
      if(count($headers) > 0){
        foreach ($headers as $key => $value) {
            $req->headers[$key] = $value;
        }
      }

      if(count($body) > 0)
      {
        $encodeBody = json_encode($body);
        $req->setBody($encodeBody);
        $req->headers["Content-Length"] = strlen($encodeBody);
      }

      $req->send() or die("Couldn't send!");
      $response = $req;
      return $response;

No, no hemos probado con otro cliente. En otras consultas (otras URLs) devuelve bien. Solamente sucede con esa consulta a la API (la de recibos).

Espero que se comprenda, sino escribo con más detalle.

Gracias por tu colaboración!!

Mariana,
Copie el código q enviaste y arme 2 archivos una clase httprequest.php y el otro archivo el index.php que seria de donde se invoca la clase. Puse los 2 archivos en una misma carpeta y probé invocar el servicio de recibos de una versión 3.4.0 la cual resulto correcta.

te copio el index.php que arme yo (el otro archivo es el mismo que me enviaste solo que para que funcione comente la primer linea (namespace)

<?php
include "./httprequest.php";

$legajo = "1";

$url = "http://localhost:80/340/mapuche/rest/agentes/{$legajo}/recibos";
$usuario_rest = "user1";
$pass_rest = "pass1";

$method = "GET";
$headers = array();
$body = array();

$req = new HttpRequest($url, $method, $usuario_rest, $pass_rest);
$req->setBody($body);

// $req->headers["Connection"] = "close";
$req->headers["Cache-Control"] = "no-cache";
if(count($headers) > 0){
	foreach ($headers as $key => $value) {
		$req->headers[$key] = $value;
	}
}

if(count($body) > 0)
{
	$encodeBody = json_encode($body);
	$req->setBody($encodeBody);
	$req->headers["Content-Length"] = strlen($encodeBody);
}

$req->send() or die("Couldn't send!");
$response = $req;
	
echo "<pre>";
	print_r($response->getResponseBody());
echo "</pre>";

Como podes ver es el mismo código donde puse las variables body y headers vacías porque no sabia como las tenían configuradas uds. Después configure mapuche con el usuario de rest user1:pass1 para invocar el servicio.

En el archivo index.php lo que hice fue imprimir la respuesta y obtuve como resultado la imagen que te adjunto. No tuvo el problema que comentas. Por lo que presumo que el problema puede estar después de la invocación al servicio, ustedes probaron imprimir por pantalla la respuesta inmediatamente después que invocan al servicio?

Saludos


ejecucion-cliente-rest.png

ejecucion-cliente-rest.png

Hice la prueba que hiciste desde mi aplicación y efectivamente el error que yo te comenté anteriormente no aparece. Pero, olvidé mencionar que HttpRequest tiene un parche con lo que estamos “solucionando” el problema desde nuestro cliente en producción.

Lo última función de HttpRequest (empiezaJson($string)) es la que se está limpiando el body corrupto. Lo forcé a que devuelva siempre true:


  /* Funcion auxiliar, busca si es un [ */
  private function empiezaJson($string)
  {
    return true;
  }

Volví a correr el cliente y sí, ahí está la cadena que menciono:



c875
[
    {
        "liquidacion": "744",
        "per_liano": "2012",
        "per_limes": "3",
        "desc_liqui": "Marzo 2012",
        "fecha_emision": "2012-04-03",
        "fecha_ultap": "2012-03-09",
        "per_anoap": "2012",
        ...

El cliente es muy similar al tuyo:

<?php

require "autoload.php";
require "bloqSeguro.php";

use \controllers\HttpRequest;



// $recibos = new Recibos();

// echo $recibos->getRecibos($usuario['legajo']);



$legajo = "1";

$url = "http://xxxxxxx/xxxx/mapuche/rest/agentes/$legajo/recibos";
$usuario_rest = "xxx";
$pass_rest = "xxxxx";

$method = "GET";
$headers = array();
$body = array();

$req = new HttpRequest($url, $method, $usuario_rest, $pass_rest);
$req->setBody($body);

$req->headers["Cache-Control"] = "no-cache";
if(count($headers) > 0){
	foreach ($headers as $key => $value) {
		$req->headers[$key] = $value;
	}
}

if(count($body) > 0)
{
	$encodeBody = json_encode($body);
	$req->setBody($encodeBody);
	$req->headers["Content-Length"] = strlen($encodeBody);
}

$req->send() or die("Couldn't send!");
$response = $req;
	
echo "<pre>";
	print_r($response->getResponseBody());
echo "</pre>";

Probamos imprimir directamente desde adentro de la clase HttpRequest, dentro de la funcion send(); justo después de que lee todos los headers, mostramos las líneas que vienen desde mapuche, sin hacerle nada, y viene así tal cual desde Mapuche.

Mariana, me pasas exactamente el como tenes los códigos que te dan error? Las 2 clases o la clase http y la porción de código que invoca, para no hacer pruebas e invertír tiempo en cosas q no tienen sentido.

saludos
Poli

Te adjunto un zip.

El cliente está hecho con angular2, hace una llamada a getRecibos.php y getRecibos.php crea el HttpRequest y devuelve el body.
Y luego, angular2 popula la tabla con los recibos del legajo pasado.

Gracias!


zipMapuche.zip (7.11 KB)

Mariana, este zip que enviaste contiene los archivos correctos?
Es decir, si yo modifico (con los datos míos) el archivo getRecibos.php y luego lo ejecuto tendría que tener el error que comentas?

Saludos

Sí.

Al abrir el archivo getRecibos.php, deberías ver la respuesta desde Mapuche.

Gracias!

Te preguntaba porq me sale bien, no me aparece ningún error!
te adjunto La ejecución del mismo.


prueba_recibos.png

prueba_recibos.png