问题
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-aliveRaw 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