You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Play Framework 2.3.8拦截器中修改响应结果体?

在Play Framework 2.3.8拦截器中修改响应结果体的实现方案

我之前维护Play Framework 2.3.x项目时,刚好处理过类似需求,结合你给出的代码片段,下面是完整可行的实现方案:

1. 实现自定义Action拦截器

我们需要继承Action.Simple并重写call方法,在获取原始响应后对其进行修改:

import play.mvc.*;
import play.libs.F.Promise;
import play.api.mvc.ScalaResult;
import play.mvc.Http;
import play.libs.Json;
import com.fasterxml.jackson.databind.JsonNode;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;

public class ModifyResponseBodyAction extends Action.Simple {

    @Override
    public Promise<Result> call(Http.Context ctx) throws Throwable {
        // 先执行后续Action,拿到原始响应的Promise
        Promise<Result> originalResultPromise = delegate.call(ctx);

        // 配置CORS跨域头(保留你原代码里的逻辑)
        ctx.response().setHeader("Access-Control-Allow-Origin", "*");

        // 对原始响应进行异步映射修改
        return originalResultPromise.map(originalResult -> {
            ScalaResult scalaResult = originalResult.toScala();
            int statusCode = scalaResult.header().status();

            // 仅处理200/201状态的成功响应
            if (statusCode == 200 || statusCode == 201) {
                try {
                    // 提取原始响应体字节数组,并转成UTF-8字符串
                    byte[] originalBodyBytes = JavaResultExtractor.getBody(originalResult, 0L);
                    String originalBody = new String(originalBodyBytes, StandardCharsets.UTF_8);

                    // --------------------------
                    // 这里是你的自定义修改逻辑
                    // 示例:给JSON响应添加外层包装
                    JsonNode originalJson = Json.parse(originalBody);
                    JsonNode modifiedJson = Json.newObject()
                            .put("success", true)
                            .put("data", originalJson);
                    String modifiedBody = Json.stringify(modifiedJson);
                    // --------------------------

                    // 构建新的Result:保留原状态码、响应头,替换响应体
                    return Results.status(statusCode)
                            .withHeaders(originalResult.headers())
                            .sendInputStream(new ByteArrayInputStream(modifiedBody.getBytes(StandardCharsets.UTF_8)));
                } catch (Exception e) {
                    // 修改过程出错(比如响应不是JSON格式),直接返回原始响应
                    return originalResult;
                }
            } else {
                // 非成功状态的响应,直接返回原始结果
                return originalResult;
            }
        });
    }
}

2. 定义注解方便使用

为了更优雅地在Controller上应用这个拦截器,我们可以定义一个自定义注解:

import play.mvc.With;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@With(ModifyResponseBodyAction.class)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ModifyResponseBody {
}

3. 在Controller中使用拦截器

直接在需要修改响应体的Controller方法或类上添加@ModifyResponseBody注解即可:

public class ApiController extends Controller {

    @ModifyResponseBody
    public Promise<Result> getUserInfo() {
        // 示例:返回原始JSON响应
        JsonNode userJson = Json.newObject()
                .put("id", 123)
                .put("name", "Ganesh");
        return Promise.pure(ok(userJson));
    }
}

关键注意事项

  • 响应体大小限制:JavaResultExtractor.getBody的第二个参数是最大允许提取的字节数,传0L表示无限制,但如果你的接口有大响应体,建议设置合理的上限避免内存溢出。
  • 非文本响应处理:如果你的接口会返回图片、文件等二进制内容,建议在判断逻辑里增加Content-Type的检查,只处理文本/JSON类型的响应。
  • 异步安全:Play 2.3.x推荐异步处理,所以我们用Promise.map来异步修改响应,避免阻塞请求线程。

内容的提问来源于stack exchange,提问作者Ganesh KuMar Ganesan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:02:15