Перенаправление PHP с кодом 307 меняет метод с POST на GET

1

В моем программном обеспечении PHP у меня есть функция самообновления, которая отправляет HTTP-запрос с методом POST на определенный URL (в PHP-скрипт). Теперь этот URL-адрес изменился (я переместил скрипт в другой каталог), но чтобы оставаться обратно совместимым, я хочу использовать скрипт по старому URL-адресу, чтобы перенаправить запрос POST в новое место. Я пытался использовать код статуса HTTP 307, но второй раз, когда PHP делает запрос, он меняет метод из POST на GET, хотя он не должен этого делать (по крайней мере, хотя это и есть код 307). Я использую PHP 5.4.29 в Windows 7 как модуль Apache (2.2.27), и я обнюхал трафик, чтобы убедиться, что HTTP 1.1 используется в запросе и ответе.

Вот как я делаю запрос POST:

<?php

$requestData = http_build_query(
    array(
        "param1" => "value1",
        // and so on...
    )
);

$requestOptions = array("http"=>
    array
    (
        "protocol_version"=>"1.1",
        "method"=>"POST",
        "header"=>array(
            "Content-type: application/x-www-form-urlencoded",
            "Connection: close",
        ),
        "content"=>$requestData,
    )
);

$requestContext = stream_context_create($requestOptions);

$serverResponse = @file_get_contents("http://localhost/old/long/path/update.php", false, $requestContext);

?>

Я пытался перенаправить вручную и автоматически с помощью PHP:

<?php

    // Redirect manually
    header("HTTP/1.1 307 Temporary Redirect");
    header("Location: http://localhost/update.php");

    // or redirect automatically
    header("Location: http://localhost/update.php", true, 307);

?>

По данным нюхательных данных, все выглядит нормально. HTTP 1.1 используется в запросе и ответе, а код 307 используется. Но во второй раз PHP отправляет запрос (в новое место, все еще с HTTP 1.1,..) он просто меняет метод на GET, и моя POST-полезная нагрузка теряется.

Опять же: это не перенаправление пользователя/браузера - я перенаправляю PHP. Я делаю свой запрос сам и вручную, хотя мое программное обеспечение и я хочу перенаправить его на новое место. Это не имеет никакого отношения к теме, связанной с безопасностью.

  • 2
    Возможный дубликат - stackoverflow.com/questions/2865289/… ?
  • 0
    Нет это не так. Другой вопрос - перенаправить пользователя или его браузер. Я не хочу это делать.
Теги:
redirect
post

2 ответа

0

Спецификация W3C HTTP/1.1 для 307 состояний:

Если код статуса 307 принимается в ответ на запрос, отличный от GET или HEAD, пользовательский агент НЕ ДОЛЖЕН автоматически перенаправлять запрос, если он не может быть подтвержден пользователем, поскольку это может изменить условия, в которых был отправлен запрос.

Дело в том, что серверу небезопасно указывать клиенту POST на другой URL-адрес, поскольку это может быть вредоносная попытка заставить клиента отправлять данные где-то, чего пользователь не намеревался, поэтому перенаправления POST невозможны.

  • 0
    Извините, но это полностью выходит за рамки моего вопроса. Я не перенаправляю пользователя или его браузер, а только свое собственное программное обеспечение. В этой ситуации злонамеренная попытка невозможна, и я не могу (и не хочу) спрашивать пользователя в середине процесса. Я перенаправляю свое собственное программное обеспечение, и пункт назначения находится на том же сервере под моим контролем. Кроме того, вы сказали, что «перенаправление POST невозможно», но это не то, что указано в спецификации, не так ли? Это просто говорит о том, что перенаправление методом POST не должно происходить без подтверждения пользователя.
  • 0
    Вы правы, это не то, что сказано в спецификации. Спецификация гласит: «Если это не может быть подтверждено пользователем», поэтому у поставщиков браузеров есть два варианта: 1) отобразить диалоговое окно подтверждения, запрашивающее у пользователя подтверждение перенаправления, или 2) не выполнять перенаправление. Похоже, что они все выбрали 2 (или, на самом деле, они решили выполнить перенаправление как GET, что не соответствует спецификации!). Я предполагаю, что они чувствовали бы, что диалог подтверждения был бы слишком техническим для большинства повседневных пользователей, которые не понимают, что такое запрос POST или каковы коннотации перенаправления.
Показать ещё 4 комментария
0

Похоже, что file_get_contents не передает данные, возможно, по причине, выделенной @daiscog.

Curl, однако, отправит перенаправленный URL:

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'http://localhost/old/long/path/update.php');   
curl_setopt($ch, CURLOPT_POST, true);    
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);  
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);  
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);    
curl_setopt($ch, CURLOPT_POSTFIELDS, $requestData);

$serverResponse = curl_exec($ch);

Однако было бы разумнее либо обрабатывать это на уровне сервера (например, переписывать URL-адрес Apache), либо просто включать новый файл в старый:

//old.php
include('path/to/new.php');
  • 0
    Спасибо за ваши рекомендации. Жаль, что file_get_contents () этого не делает. Я не понимаю, как я должен сказать PHP, что было подтверждение пользователя ... это немного бессмысленно. Но я буду использовать вашу рекомендацию и обрабатывать ее на уровне сервера самостоятельно: я создал прокси-скрипт, который в основном выполняет то же самое, что и запрашивающий скрипт (как в моем примере кода выше), но вместо этого я передаю $ _POST в http_build_query (). Теперь, похоже, работает как ожидалось. cUrl - это расширение, которое я не всегда ожидаю. include () работает только локально.
  • 1
    Нет проблем. Re "include only works locally" почему это проблема? Старый URL находится на другом сервере, чем новый? У меня сложилось впечатление, что вы просто изменили URL-адрес обновления на одном сайте, поэтому old.php и new.php будут находиться на одном сервере
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню