yiisoft / yii2

Yii 2: The Fast, Secure and Professional PHP Framework
http://www.yiiframework.com
BSD 3-Clause "New" or "Revised" License
14.24k stars 6.91k forks source link

Redirecting problem in Internet Explorer 11 (IE11) #17434

Closed art40100 closed 5 years ago

art40100 commented 5 years ago

What steps will reproduce the problem?

Performing an ajax request and doing a redirect from it. (Issue when using Internet Explorer 11 (IE11)) Related (same issue) #9670

What is the expected result?

A successful redirect to given URL in function Response::redirect()

What do you get instead?

No redirect! jokeie11

Additional info

Using 308 statusCode (default is 302) solves the problem in general but it is probably not the right way to do this. return Yii::$app->getResponse()->redirect(['aaa/view', 'id' => $this->lid], 308);

Q A
Yii version 2.0.22
PHP version 5.6.40
Operating system W10x64
art40100 commented 5 years ago

Quick and dirty solution - extending the Response class and overriding redirect()

class CResponse extends \yii\web\Response
{
    /**
     * @inheritdoc
     */
    public function redirect($url, $statusCode = 302, $checkAjax = true)
    {
        $browser = Yii::$app->browser;
        $browserName = $browser->getName();
        if (Yii::$app->getRequest()->isAjax 
            && ($browserName === $browser::IE)
        ) {
            return parent::redirect($url, 308, $checkAjax);
        } else {
            return parent::redirect($url, $statusCode, $checkAjax);
        }
    }
}
samdark commented 5 years ago

@art40100 what's Yii::$app->browser?

alex-code commented 5 years ago

This should work in JS to use the frameworks redirect handling.

var ua = window.navigator.userAgent;
if (ua.indexOf('MSIE ') > 0 || ua.indexOf('Trident/') > 0 || ua.indexOf('Edge/') > 0) {
  $(document).ajaxSend(function(event, jqXHR, ajaxOptions) {
      jqXHR.setRequestHeader('X-Ie-Redirect-Compatibility', 'true');
  });
}
art40100 commented 5 years ago

@art40100 what's Yii::$app->browser?

in config/main.php

'components' => [
    'browser' => [
        'class' => 'Sinergi\BrowserDetector\Browser',
    ]
];

A library installed in my project via composer (https://packagist.org/packages/sinergi/browser-detector)

samdark commented 5 years ago

OK. That may work for you but isn't a good solution for the framework.

kamarton commented 5 years ago

@art40100 please check this fix: https://github.com/yiisoft/yii2/pull/17525

fl0v commented 4 years ago

https://github.com/yiisoft/yii2/blob/561242be5e500fcba61e8628295f848d4682f9a9/framework/web/Response.php#L873

The fix applyed breaks compatibility by removing check for X-Ie-Redirect-Compatibility header used in previos releases: https://github.com/yiisoft/yii2/blob/2927a7af1c40ba3d1294b3c9bfcbc7a70bd4c9b1/framework/web/Response.php#L867

There are special windows versions (for tablets or IoT devices) that send custom user agent that does not include standard IE11 signature checked by preg_match('/Trident.*\brv:11\./' /* IE11 */, $request->userAgent). Ex:

Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; Tablet PC 2.0)

It could be usefull to refactor the code to be able to activate this IE11 hack using request headers as before release 2.0.26 and maybe add a \yii\web\Response flag

kamarton commented 4 years ago

This is true. I do not know that I did not notice the other versions of IE checking.

https://github.com/SilverFire/jquery-pjax/blob/017ef68cc7fe998377e37b380ccf645e3714ecca/jquery.pjax.js#L235-L237

      if (ua.indexOf('MSIE ') > 0 || ua.indexOf('Trident/') > 0 || ua.indexOf('Edge/') > 0) {
        xhr.setRequestHeader('X-Ie-Redirect-Compatibility', 'true')
      }