如何在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
相关产品推荐
相关产品推荐

