Error 406 Not Acceptable with idHTTP on Android

一世执手 提交于 2020-01-11 09:56:08

问题


I'm trying to post a insert on a MySQL database using idHTTP and a PHP script. This is the PHP script to insert in the database:

    $mysqli = new mysqli($servidor, $usuario, $senha, $banco);

    // Caso algo tenha dado errado, exibe uma mensagem de erro
    if (mysqli_connect_errno()) trigger_error(mysqli_connect_error());

    $iduser         = quoted_printable_decode($_POST['iduser']);
    $nome           = quoted_printable_decode($_POST['nome']);
    $data           = quoted_printable_decode($_POST['data']);
    $hora           = quoted_printable_decode($_POST['hora']);
    $mensagem       = quoted_printable_decode($_POST['mensagem']);
    $latitude       = quoted_printable_decode($_POST['latitude']);
    $longitude      = quoted_printable_decode($_POST['longitude']);
    $imagem         = $_FILES["imagem"]['tmp_name'];
    $tamanho        = $_FILES['imagem']['size'];

    header($_SERVER["SERVER_PROTOCOL"] . " 200 OK"); 
    header('Content-Type: text/plain; charset="utf-8"');

    if ( $imagem != "none" )
    {
        $fp = fopen($imagem, "rb");
        $conteudo = fread($fp, $tamanho);
        $conteudo = addslashes($conteudo);
        fclose($fp);

        $queryInsercao = "INSERT INTO tabpainel (iduser, nome, data, hora, mensagem, latitude, longitude, imagem) VALUES ('$iduser', '$nome', '$data','$hora','$mensagem', '$latitude', '$longitude', '$conteudo')";

        mysqli_query($mysqli,$queryInsercao) or die("Algo deu errado ao inserir o registro. Tente novamente.");

        if (mysqli_affected_rows($mysqli) > 0)
                include 'baixarpainel.php';
            else
                print utf8_encode("Não foi possível inserir o registro");
        }
        else
            print utf8_encode("Não foi possível carregar a imagem.");
  ?>

And in Delphi, i'm using this:

      FormPHP := TIdMultiPartFormDataStream.Create;

      FormPHP.AddFile       ('imagem',    AImagem,    'image/jpeg');
      FormPHP.AddFormField  ('iduser',    AIDUser,    'utf-8');
      FormPHP.AddFormField  ('nome',      ANome,      'utf-8');
      FormPHP.AddFormField  ('data',      AData,      'utf-8');
      FormPHP.AddFormField  ('hora',      AHora,      'utf-8');
      FormPHP.AddFormField  ('mensagem',  AMensagem,  'utf-8');
      FormPHP.AddFormField  ('latitude',  '1');
      FormPHP.AddFormField  ('longitude', '1');

      Response := TStringStream.Create('',TEncoding.UTF8);

      HTTP:= TIdHTTP.Create(self);
 HTTP.Post('http://addressexample.com/cadastro.php',FormPHP,Response);

It was working fine until a had to change the hosting company. With Hostinger was ok but with Hostgator it doesn't. With Hostgator the idHTTP raise an exception in the class EIdHTTPProtocalException with the message: "HTTP/1.1 406 Not Acceptable". The Hostgator support has already disabled the mod_security, that could cause the problem.

This exception only occurs on Android. Using the same app on Windows, it works fine.

UPDATE: I've tried another thing. The PHP script is this:

    // Conecta-se ao banco de dados MySQL
    $mysqli = new mysqli($servidor, $usuario, $senha, $banco);

    // Caso algo tenha dado errado, exibe uma mensagem de erro
    if (mysqli_connect_errno()) trigger_error(mysqli_connect_error());

    # Instanciando o XMLWriter
    $xml = new XMLWriter;
    $xml->openMemory();

    # Definindo o encoding do XML
    $xml->startDocument( '1.0', 'UTF-8');

    # Primeiro elemento do XML
    $xml->startElement("DATAPACKET");
    $xml->writeAttribute("version", "2.0");
        $xml->StartElement("METADATA");
            $xml->startElement("FIELDS");
                $xml->startElement("FIELD");
                    $xml->writeAttribute("attrname", "id");
                    $xml->writeAttribute("fieldtype", "I4");
                $xml->endElement();
                $xml->startElement("FIELD");
                    $xml->writeAttribute("attrname", "iduser");
                    $xml->writeAttribute("fieldtype", "String");
                    $xml->writeAttribute("Width", "30");
                $xml->endElement();
                $xml->startElement("FIELD");
                    $xml->writeAttribute("attrname", "nome");
                    $xml->writeAttribute("fieldtype", "String");
                    $xml->writeAttribute("Width", "200");
                $xml->endElement();
                $xml->startElement("FIELD");
                    $xml->writeAttribute("attrname", "data");
                    $xml->writeAttribute("fieldtype", "String");
                    $xml->writeAttribute("Width", "8");
                $xml->endElement();
                $xml->startElement("FIELD");
                    $xml->writeAttribute("attrname", "hora");
                    $xml->writeAttribute("fieldtype", "String");
                    $xml->writeAttribute("Width", "5");
                $xml->endElement();
                $xml->startElement("FIELD");
                    $xml->writeAttribute("attrname", "mensagem");
                    $xml->writeAttribute("fieldtype", "String");
                    $xml->writeAttribute("Width", "3000");
                $xml->endElement();
                $xml->startElement("FIELD");
                    $xml->writeAttribute("attrname", "latitude");
                    $xml->writeAttribute("fieldtype", "r8");
                $xml->endElement();
                $xml->startElement("FIELD");
                    $xml->writeAttribute("attrname", "longitude");
                    $xml->writeAttribute("fieldtype", "r8");
                $xml->endElement();
                $xml->startElement("FIELD");
                    $xml->writeAttribute("attrname", "imagem");
                    $xml->writeAttribute("fieldtype", "bin.hex");
                    $xml->writeAttribute("subtype", "Binary");
                $xml->endElement();
            $xml->endElement(); //FIELDS
        $xml->endElement(); //METADATA

        $xml->StartElement("ROWDATA"); 
        # Query na tabela escolhida
        $rs_table = $mysqli->query("select * from tabpainel ORDER BY id DESC LIMIT 50");
        while($table = $rs_table->fetch_array(MYSQLI_ASSOC))
            {
                # Transformando array em objeto
                $table = (object)$table;
                # Criando elemento tabela
                $xml->StartElement("ROW");
                # Setando os atributos
                    $xml->writeAttribute("id", "$table->id");
                    $xml->writeAttribute("iduser", "$table->iduser");
                    $xml->writeAttribute("nome", "$table->nome");
                    $xml->writeAttribute("data", "$table->data");
                    $xml->writeAttribute("hora", "$table->hora");
                    $xml->writeAttribute("mensagem", "$table->mensagem");
                    $xml->writeAttribute("latitude", "$table->latitude");
                    $xml->writeAttribute("longitude","$table->longitude");
                    $xml->writeAttribute("imagem", base64_encode("$table->imagem"));
                $xml->endElement();
            }
        # Fechando o ROWDATA
        $xml->endElement();
    # Fechando o elemento DATAPACKET
    $xml->endElement();
    # Encerrando a conexao
    //$con->close();
    # Definindo cabecalho de saida
    header("content-type: application/xml; charset=utf-8");
    # Imprimindo a saida do XML
    print $xml->outputMemory(true);
?>

And I used a http.get to receive the xml:

Http.HandleRedirects:= true;
Http.request.useragent := 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; MAAU)';
MS.Text:= Http.get('http://addressexample.com/baixarpainel.php');
 MS.SaveToFile(FarquivoBaixado);

And this worked just fine on Android too. The problem remains only http.post on Android.


回答1:


TIdHTTP works exactly the same way on all platforms, as Indy uses a single cross-platform codebase. So the generated HTTP request should be exactly the same on all platforms.

An HTTP 406 error happens when the HTTP request includes an Accept header that does not specify any media type that the server is capable of rendering the response in. Per RFC 2616 Section 14.1:

If no Accept header field is present, then it is assumed that the client accepts all media types. If an Accept header field is present, and if the server cannot send a response which is acceptable according to the combined Accept field value, then the server SHOULD send a 406 (not acceptable) response.

Your PHP script is sending a text/plain response, so if you send an Accept header that does not allow text/plain then that can cause a 406 error. It sounds like Hostgator is enforcing that more than Hostinger does.

By default, TIdHTTP sets its Request.Accept property to the following string value:

'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'

Which technically allows all media types via */*, but just with a lower priority than some other media types. But that default should still be enough to allow a text/plain response, if the server implements Accept handling correctly.

You need to contact Hostgator and discuss the issue with them, as the problem is on their end, not yours.

That being said, since you know the server response is always text/plain, you could just add the following to your code before calling Post():

HTTP.Request.Accept := 'text/plain';
HTTP.Request.AcceptCharset := 'utf-8';



回答2:


After long hours trying to solve, this is what happened.

On Windows, the application was working fine, and when I tried using HTTP.GET i imagined that couldn't be on server's end the problem, but on my request. So then, i started opening the headers of request and response both on Windows and Android using this code:

Astr.Add('Response text: ' + Http.Response.ResponseText);
Astr.Add(#13);  
Astr.Add('Raw Headers Response: ' + HTTP.Response.RawHeaders.Text);
Astr.Add(#13);
Astr.Add('Raw Headers Request: ' + HTTP.Request.RawHeaders.Text);

This was the message i've got on Android:

Response text: HTTP/1.1 406 Not Acceptable

Raw Headers Response: Server: nginx/1.10.2
Date: ...
Content-Type: text/html;
charset=iso-8859-1
Content-Length:226
Connection: keep-alive

Raw Headers Request: Connection: keep-alive
Content-Type: multipart/form-data; boundary=------(somenumbers)
Content-Length: 0 Host: myhost Accept:text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8 Accept-Encoding: identity
User-Agent: ...

And this was the message on Windows

Response text: HTTP/1.1 200 OK

Raw Headers Request: Server: nginx/1.10.2 Date: ... Content-Type: application/xml Connection: close Vary: Accept-Encoding,User-Agent

Raw Headers Request: Connection: keep-alive

Content-Type: multipart/form-data; boundary=--------(numebrs) Content-Length: 0 Host: myhost Accept:text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8 User-Agent: ...

The same app on different platforms were sending different headers on Request. On Android, the idHTTP was sending an Accept-Encoding that on Windows was not. So I tried adding this: Http.Request.AcceptEncoding:= '*'; before the HTTP.POST and it worked! I received the xml just as expected.

I don't know why the idHTTP was changing the Request Accept-Encoding, but I had to specify another one and I chose this one because of MDN definition:

*

Matches any content encoding not already listed in the header. This is the default value if the header is not present. It doesn't mean that any algorithm is supported; merely that no preference is expressed.




回答3:


I was able to resolve this issue by simple changing user agent string. I think remote machine(server) has some security installed.

I just set the Request -> UserAgent to:

Mozilla/5.0 (Android 4.4; Mobile; rv:41.0) Gecko/41.0 Firefox/41.0

and now it works !



来源:https://stackoverflow.com/questions/40851649/error-406-not-acceptable-with-idhttp-on-android

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!