【已解决】两个响应数据中间的问题

大当家叫我来宕机

问题描述

定义了两个中间件:

  • DesensitizeMiddleware 响应数据注解脱敏中间件
  • ResponseCaseConverter 响应数据下划线转驼峰

现出现一个问题:当我定一个字段id_card,数据脱敏并将字段名变成idCard,这个时候,就不能脱敏成功,需将ResponseCaseConverter移除掉,才能正常响应脱敏

中间件配置:

<?php

return [
    '@' => [
        \Landao\WebmanCore\Middleware\DesensitizeMiddleware::class,
        \Landao\WebmanCore\Middleware\ResponseCaseConverter::class
    ]
];

DesensitizeMiddleware代码:

<?php

namespace Landao\WebmanCore\Middleware;

use Landao\WebmanCore\Helpers\DesensitizeHelper;
use Landao\WebmanCore\ParseAnnotation\DesensitizeParse;
use Webman\Http\Request;
use Webman\Http\Response;
use Webman\MiddlewareInterface;

/**
 * 注解脱敏中间件
 */
class DesensitizeMiddleware implements MiddlewareInterface
{
    /**
     * 响应数据的根路径
     * @var string
     */
    protected $rootPath = 'data';

    public function process(Request $request, callable $handler): Response
    {
        // 先执行后续中间件和控制器,获取响应
        $response = $handler($request);

        // 获取当前控制器和方法
        $controller = $request->controller;
        $action = $request->action;

        // 获取脱敏规则
        $desensitizeRules = DesensitizeParse::getDesensitizeRules($controller, $action);
        if (empty($desensitizeRules)) {
            return $response;
        }

        // 尝试解析响应内容
        $content = $response->rawBody();
        $data = json_decode($content, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            return $response;
        }
        // 支持根路径配置(如API响应格式为 {code:200, data:{...}})
        $targetData = &$data;
        if (!empty($this->rootPath)) {
            $rootFields = explode('.', $this->rootPath);
            foreach ($rootFields as $field) {
                if (!isset($targetData[$field])) {
                    // 根路径不存在,记录日志并返回原始响应
                    return $response;
                }
                $targetData = &$targetData[$field];
            }
        }
        // 应用脱敏规则
        if (is_array($targetData)) {
            // 根数据是数组,遍历每个元素处理
            foreach ($targetData as &$item) {
                if (is_array($item)) {
                    $this->processArrayItem($item, $desensitizeRules);
                }
            }
        } else {
            // 根数据是对象,直接处理
            foreach ($desensitizeRules as $rule) {
                $this->applyDesensitize($targetData, $rule['field'], $rule['rule']);
            }
        }

        $response->withBody(json_encode($data, JSON_UNESCAPED_UNICODE));
        // 更新响应内容
        return $response;
    }
}

ResponseCaseConverter代码:

<?php

namespace Landao\WebmanCore\Middleware;

use Landao\WebmanCore\Helpers\CamelHelper;
use Webman\Http\Request;
use Webman\Http\Response;
use Webman\Middleware;

/**
 * 响应数据下划线转驼峰
 */
class ResponseCaseConverter extends Middleware
{
    public function process(Request $request, callable $handler): Response
    {
        // 先执行后续中间件获取响应
        $response = $handler($request);

        // 只处理JSON响应
        $contentType = $response->getHeader('Content-Type');
        if (strpos($contentType, 'application/json') !== false) {
            $body = $response->rawBody();
            $data = json_decode($body, true);

            // 检查JSON解码是否成功
            if (json_last_error() === JSON_ERROR_NONE && is_array($data)) {
                // 使用CamelHelper转换键名
                $convertedData = CamelHelper::recursiveConvertNameCaseToCamel($data);

                // 更新响应内容
                $newBody = json_encode($convertedData, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
                $response = $response->withBody($newBody);
            }
        }
        return $response;
    }
}

是中间件顺序配置错了吗?或者有没有更好的不侵入代码,去处理这两个业务?

150 1 0
1个回答

nitron

中间件是洋葱模型

  • 暂无评论
🔝