session 为啥保存了,使用的时候却没值?

andyzu

同一个文件里:
我在A方法里,

$session = $request->session();
$session->set('session_key', $result['session_key']);
// $session_key = $session->get('session_key');

并且打印 $session_key 确认保存了。

我在B方法里:

$session = $request->session();
$session_key = $session->get('session_key');
$has = $session->has('session_key');

打印 $session_key 是 null , 打印 $has 是 false 。
为啥??

截图

429 3 0
3个回答

walkor

发一个能复现问题的完整代码和步骤

  • andyzu 2023-09-17

    老大,我发了,您过目!

  • walkor 2023-09-17

    你这个我测不了。看下是不是每次请求都产生了一个新的session文件

  • andyzu 2023-09-18

    是的

  • walkor 2023-09-18

    那应该是前端没传PHPSID的cookie

  • andyzu 2023-09-18

    老大,这个貌似跟前端没关系,因为前段传code 过来,我从微信获取的数据,我打印是确定有session_key , 然后我才存到 session 里的。或者老大您告诉我应该咋解决,我菜鸟一枚!

  • walkor 2023-09-18

    截图
    session是依赖cookie实现的,浏览器每次请求会带上cookie,服务端就从cookie中得到session id,然后从磁盘或者redis找对应session id的文件或数据,才能还原上次记录的session

andyzu
// 同一个文件的 方法 A :
public function code2session(Request $request){

        $param = [
            'code' => $request->input('code'),
        ];

        // 进行参数校验
        $validate = new Code2SessionValidate();
        if (!$validate->check($param)) {
            return json($validate->getError());
        }

        $app = Factory::miniProgram(config('myconfig.wechat.config'));
        $result = $app->auth->session($param['code']);

        if (array_key_exists('openid', $result) && array_key_exists('session_key', $result)) {
            $key = 'openid:'.$result['openid'];
            $isExists = Redis::exists($key);
            if (!$isExists) {
                $fields = [
                    'openid' => $result['openid'],
                    'session_key' => $result['session_key'],
                ];
                Redis::hMSet($key, $fields);
            }

            $session = $request->session();
            $session->set('session_key', $result['session_key']);       // 我确定 $result['session_key'] 有值

        } else {
            return json([
                'code' => config('myconfig.statusCode.HTTP_FAIL')[0],
                'msg' => config('myconfig.statusCode.HTTP_FAIL')[1],
                'data' => $result,
            ]);
        }

        return json([
            'code' => config('myconfig.statusCode.HTTP_OK')[0],
            'msg' => config('myconfig.statusCode.HTTP_OK')[1],
            'data' => $result,
        ]);
// 同一个文件的 方法B:
public function getPhoneNumber(Request $request)
    {
        $param = [
            'openid' => $request->input('openid'),
            'encryptedData' => $request->input('encryptedData'),
            'iv' => $request->input('iv'),
        ];

        // 进行参数校验
        $validate = new GetPhoneNumberValidate();
        if (!$validate->check($param)) {
            return json($validate->getError());
        }

        $app = Factory::miniProgram(config('myconfig.wechat.config'));
        $session = $request->session();
        $session_key = $session->get('session_key');        // null
        $all = $session->all();                                     // 空数组
        $has = $session->has('session_key');            // false

        $key = 'openid:'.$param['openid'];
        $redis_value = Redis::hGetAll($key);

        $result = $app->encryptor->decryptData($redis_value['session_key'], $param['iv'], $param['encryptedData']);

        if (array_key_exists('purePhoneNumber', $result)){
            // 设置哈希表的多个字段和值
            $fields = [
                'openid' => $redis_value['openid'],
                'session_key' => $redis_value['session_key'],
                'countryCode' => $result['countryCode'],
                'purePhoneNumber' => $result['purePhoneNumber'],
            ];
            // 将字段和对应的值同时设置到哈希表中
            Redis::hMSet($key, $fields);

            $res['countryCode'] = $result['countryCode'];
            $res['purePhoneNumber'] = $result['purePhoneNumber'];

        }else{
            return json([
                // 'HTTP_FAIL' => [200110, '请求失败'],
                'code' => config('myconfig.statusCode.HTTP_FAIL')[0],
                'msg' => config('myconfig.statusCode.HTTP_FAIL')[1],
                'data' => $result,
            ]);
        }

        return json([
            // 'HTTP_OK' => [200100, '请求成功'],
            'code' => config('myconfig.statusCode.HTTP_OK')[0],
            'msg' => config('myconfig.statusCode.HTTP_OK')[1],
            'data' => $res,
        ]);

    }
// session 的配置文件:
<?php
/**
 * This file is part of webman.
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the MIT-LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @author    walkor<walkor@workerman.net>
 * @copyright walkor<walkor@workerman.net>
 * @link      http://www.workerman.net/
 * @license   http://www.opensource.org/licenses/mit-license.php MIT License
 */

use Webman\Session\FileSessionHandler;
use Webman\Session\RedisSessionHandler;
use Webman\Session\RedisClusterSessionHandler;

return [

    'type' => 'file', // or redis or redis_cluster

    'handler' => FileSessionHandler::class,

    'config' => [
        'file' => [
            'save_path' => runtime_path() . '/sessions',
        ],
        'redis' => [
            'host' => '127.0.0.1',
            'port' => 6379,
            'auth' => 'Abc123',
            'timeout' => 2,
            'database' => '',
            'prefix' => 'phc_',
        ],
        'redis_cluster' => [
            'host' => ['127.0.0.1:7000', '127.0.0.1:7001', '127.0.0.1:7001'],
            'timeout' => 2,
            'auth' => '',
            'prefix' => 'phc_',
        ]
    ],

    'session_name' => 'PHPSID',

    'auto_update_timestamp' => false,

    'lifetime' => 7*24*60*60,

    'cookie_lifetime' => 365*24*60*60,

    'cookie_path' => '/',

    'domain' => '',

    'http_only' => true,

    'secure' => false,

    'same_site' => '',

    'gc_probability' => [1, 1000],

];
  • efnic 2023-09-18

    常识问题,小程序开发时候,是没有Session的。

  • andyzu 2023-09-18

    虽然是给小程序写的接口,但是接口内部拿到数据,然后存到 session 里,在另一个方法不能调用?这说不通啊

  • efnic 2023-09-18

    你们前端太菜,后端也不理解session原理。
    建议百度:wx.request cookie

  • efnic 2023-09-18

    老大也说:session是依赖cookie实现的,浏览器每次请求会带上cookie,服务端就从cookie中得到session id,然后从磁盘或者redis找对应session id的文件或数据,才能还原上次记录的session。

    浏览器是支持cookie和session的,当服务器的响应头内包含Set-Cookie头时,浏览器会把里面的键值对保存起来,下次请求自动携带。
    换句话说,小程序的wx.request只是发起请求,返回结果;需要你们的前端开发人员,解析出header头内容存储起来,下次请求时也携带。

    【下面楼层,我做了一个中间件,可以用请求头内token值,作为session_id兼容webman的Session】

efnic
<?php

namespace app\middleware;

use support\Request;
use Webman\Http\Response;
use Webman\MiddlewareInterface;

/**
 * Token转换Session
 * - 从请求头获取token值,设置session_id
 */
class Session implements MiddlewareInterface
{
    /**
     * @param Request|\Webman\Http\Request $request
     * @param callable $handler
     * @return Response
     */
    public function process(Request|\Webman\Http\Request $request, callable $handler): Response
    {
        $token = $request->header('token');
        if ($token && ctype_alnum($token) && strlen($token) <= 70) {
            $request->setSid($token);
        }
        return $handler($request);
    }
}

此中间件放到全局中间件内,兼容webman的session中间件。
原理是,用客户端请求头内的token,作为sid。

  • andyzu 2023-09-19

    感谢大神,但是我还是没转过这弯,那如果我的代码跟前端没半毛钱关系,我如何使用 session , 我突然感觉我不会用session 了.....

  • 1 2023-09-19

    session是依赖cookie实现的,浏览器每次请求会带上cookie,服务端就从cookie中得到session id,然后从磁盘或者redis找对应session id的文件或数据,才能还原上次记录的session

🔝