How to add HTTP headers at specific action?

Hello! I am using advanced template of Yii2 application. Created this common action:




<?php


namespace common\actions;


use yii\base\Action;

use Yii;


class ShareIdentityAction extends Action

{

    public function run($outerSessId = '', $token = '')

    {

        // @@@ Put headers here


        if ($token) return $this->loginWithToken($token);

        else if ($outerSessId && Yii::$app->user->identity) return $this->requestToken($outerSessId);

        return false;

    }

    // Suppose there are full-featured functions (I just cut a little).

    protected function requestToken($outerSessId) return false;

    protected function loginWithToken($token) return false;

}



It’s properly referenced in SignInControllers of both sites (frontend and backend) and whole code is working fine ― token is generated and can be used to login on other context (backend <-> frontend). And implementing AJAX POST cross-origin requests depends on these headers:




Yii::$app->response->getHeaders()->add('Access-Control-Max-Age', '10');

Yii::$app->response->getHeaders()->add('Access-Control-Allow-Origin', 'http:backend.domain.com http:domain.com');

Yii::$app->response->getHeaders()->add('Access-Control-Allow-Methods', 'POST');

Yii::$app->response->getHeaders()->add('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With');



(Don’t mind http: without slashes. Because of I’m newbie here, I can’t post links ever in code…)

I put 'em in the beginning of run function. Unfortunately, client doesn’t see new headers, also getHeaders()-&gt;set doesn’t work at this point.

It’s maybe because headers were sent already. How actually I can add headers at specific action?

you should call Yii::$app->response->headers->set() to set header value which will overwrite an existing header, I find it weird why set is not working for you there is possibility these headers are overwritten, maybe remove other actions and test this action alone by itself

here is an example action I used to test it works fine with a newly create yii app


<?php


namespace app\actions;


use Yii;


class FooAction extends \yii\base\Action

{

    public function run()

    {

        Yii::$app->response->headers->set('Pragma', 'cache');

        return 'foo';

    }

}




// sitecontroller which uses my FooAction

    public function actions()

    {

        // ...

        return [

            'foo' => [

                'class' => 'app\actions\FooAction'

            ]

        ];

        // ...

    }



That’s exact thing I do except there is no set but add. Unfortunately, both variants don’t work. Bump. Where I need put my headers? Are they sent before action run?

By the way, I have headers in Yii object:




yii\web\HeaderCollection Object

(

    [_headers:yii\web\HeaderCollection:private] => Array

        (

            [access-control-max-age] => Array

                (

                    [0] => 10

                )


            [access-control-allow-origin] => Array

                (

                    [0] => http:backend.domain.com http:domain.com

                )


            [access-control-allow-methods] => Array

                (

                    [0] => POST

                )


            [access-control-allow-headers] => Array

                (

                    [0] => Content-Type, Authorization, X-Requested-With

                )


        )


)



But they seem not appearing on client. What can cause this?

Hi Rodion Borisov,

The actual problem is handling Cross-Origin request?

Can you go through this page may give you best result!

http://www.yiiframework.com/doc-2.0/yii-filters-cors.html

Example code with headers







    /**

     * @inheritdoc

     */

    public function behaviors() {

        return [

            'corsFilter' => [

                'class' => \yii\filters\Cors::className(),

                'only' => ['getcsrf'],//List of actions to be applied

                'cors' =>

                [

                    'Origin' => ['*'],

                    'Access-Control-Request-Method' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],

                    'Access-Control-Request-Headers' => ['http://10.10.3.50:3000'],// Even you can filter by IP Address

                    'Access-Control-Allow-Credentials' => true,

                    'Access-Control-Max-Age' => 86400,

                    'Access-Control-Expose-Headers' => []

                ]

            ],

//Other access control options of Yii

            'access' => [

                'class' => AccessControl::className(),

                'only' => ['logout'],

                'rules' => [

                    [

                        'actions' => ['logout'],

                        'allow' => true,

                        'roles' => ['@'],

                    ],

                ],

            ],

            'verbs' => [

                'class' => VerbFilter::className(),

                'actions' => [

                    'logout' => ['post'],

                ],

            ],

        ];

    }




1 Like

I am not sure what your code look likes but as you mentioned in your original post you have an action which you are using in both back-end as well front-end app, this should not by any different the example I gave you is also an action which I test with the basic app and it works. perhaps some other part of your code is overwriting the headers.

if you are trying to add CORS headers then you might as well use cors filter provided by Yii as @Arockia mentioned that will much better solution.

Meow, that works! Thank you, Arokia Johnson!

I have added this to common configuration:




    'as corsFilter' => [

        'class' => \yii\filters\Cors::className(),

        'cors' =>

        [

            'Origin' => [\Yii::getAlias('@backendUrl'), \Yii::getAlias('@frontendUrl')],

            'Access-Control-Request-Method' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],

            'Access-Control-Allow-Credentials' => true,

            'Access-Control-Max-Age' => 86400

        ]

    ]



and this to frontend configuration:




    'as corsFilter' => [

        'only' => ['user/sign-in/bind-identity']

    ]



yii2-starter-kit merges these configurations in result and cross-origin request are working fine now.