Ошибка 406 Недопустимо с idHTTP на Android

Я пытаюсь разместить вставку в базу данных MySQL, используя idHTTP и PHP-скрипт. Это скрипт PHP для вставки в базу данных:

    $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.");
?>

И в Delphi я использую это:

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

Он работал нормально, пока не пришлось сменить хостинг-компанию. С Hostinger все было в порядке, но с Hostgator нет. С Hostgator idHTTP вызывает исключение в классе EIdHTTPProtocalException с сообщением: «HTTP / 1.1 406 Недопустимо». Поддержка Hostgator уже отключила mod_security, это может вызвать проблему.

Это исключение происходит только на Android. Используя то же самое приложение на Windows, оно отлично работает.

ОБНОВЛЕНИЕ: я попробовал другую вещь. PHP-скрипт такой:

    // 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);
?>

И я использовал http.get, чтобы получить 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);

И это прекрасно работало на Android тоже. Проблема остается только http.post на Android.

3

Решение

TIdHTTP работает одинаково на всех платформах, так как Indy использует одну кроссплатформенную кодовую базу. Таким образом, сгенерированный HTTP-запрос должен быть одинаковым на всех платформах.

HTTP 406 ошибка возникает, когда HTTP-запрос включает Accept заголовок, в котором не указан тип носителя, на который сервер способен отрисовать ответ. RFC 2616 Раздел 14.1:

Если поле заголовка Accept отсутствует, предполагается, что клиент принимает все типы мультимедиа. Если присутствует поле заголовка Accept, и если сервер не может отправить ответ, который является приемлемым согласно комбинированному значению поля Accept, то сервер ДОЛЖЕН отправить 406 (не приемлемый) ответ.

Ваш PHP-скрипт отправляет text/plain ответ, так что если вы отправите Accept заголовок, который не позволяет text/plain то это может вызвать 406 ошибка. Похоже, Hostgator обеспечивает это больше, чем Hostinger.

По умолчанию, TIdHTTP устанавливает его Request.Accept свойство для следующего строкового значения:

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

Который технически позволяет все типы медиа через */*, но только с более низким приоритетом, чем некоторые другие типы носителей. Но этого значения по умолчанию должно быть достаточно, чтобы text/plain ответ, если сервер реализует Accept обрабатывать правильно.

Вам нужно связаться с Hostgator и обсудить с ними проблему, так как проблема с их стороны, а не с вашей.

При этом, поскольку вы знаете, ответ сервера всегда text/plainВы можете просто добавить следующее в свой код перед вызовом Post():

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

Другие решения

После долгих часов попыток решить, вот что случилось.

В Windows приложение работало нормально, и когда я попытался использовать HTTP.GET, я представил, что проблема может быть не на стороне сервера, а по моему запросу. Итак, я начал открывать заголовки запроса и ответа на Windows и Android, используя этот код:

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

Это было сообщение, которое я получил на Android:

Текст ответа: HTTP / 1.1 406 Недопустимо

Ответ необработанных заголовков: Сервер: nginx / 1.10.2
Дата: …
Content-Type: text / html;
кодировка = изо-8859-1
Content-Length: 226
Подключение: keep-alive

Запрос необработанных заголовков: соединение: keep-alive
Content-Type: multipart / form-data; граница = —— (somenumbers)
Длина контента: 0
Host: myhost
Accept: Текст / HTML, приложение / XHTML + XML, приложение / XML; д = 0,9,/; Д = 0,8
Accept-Encoding: личность
Пользователь-агент: …

И это было сообщение в Windows

Текст ответа: HTTP / 1.1 200 OK

Запрос необработанных заголовков: Сервер: nginx / 1.10.2
Дата: …
Тип контента: application / xml
Подключение: закрыть
Варьируется: Accept-Encoding, User-Agent

Запрос необработанных заголовков: соединение: keep-alive

Content-Type: multipart / form-data; граница = ——— (numebrs)
Длина контента: 0
Host: myhost
Accept: Текст / HTML, приложение / XHTML + XML, приложение / XML; д = 0,9,/; Д = 0,8
Пользователь-агент: …

Одно и то же приложение на разных платформах отправляло разные заголовки по запросу. На Android idHTTP отправлял кодировку Accept, а на Windows — нет. Поэтому я попытался добавить это: Http.Request.AcceptEncoding:= '*'; до HTTP.POST и все заработало! Я получил XML, как и ожидалось.

Я не знаю, почему idHTTP изменил кодировку принятия запроса, но мне пришлось указать другую, и я выбрал эту из-за определения MDN:

*

Соответствует любой кодировке содержимого, еще не указанной в заголовке. Это
значение по умолчанию, если заголовок отсутствует. Это не значит что
любой алгоритм поддерживается; просто, что никакое предпочтение не выражено.

0

Мне удалось решить эту проблему, просто изменив строку агента пользователя. Я думаю, что на удаленной машине (сервере) установлена ​​некоторая безопасность.

Я просто установил Запрос -> UserAgent:

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

и теперь это работает!

0
По вопросам рекламы [email protected]