Feature/dubbo3.2 resteasy response context result support (#12854)

* resteasy response context result support

* some detail

---------

Co-authored-by: suncr <suncairong@moresec.cn>
This commit is contained in:
suncairong163 2023-08-07 14:54:13 +08:00 committed by GitHub
parent b39a1e82e1
commit e7fa74beb9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 91 additions and 10 deletions

View File

@ -0,0 +1,54 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.rpc.protocol.rest.extension.resteasy.filter;
import org.jboss.resteasy.specimpl.BuiltResponse;
/**
* wrapper resteasy BuiltResponse
*/
public class DubboBuiltResponse extends BuiltResponse {
// user reset entity
private boolean resetEntity;
public DubboBuiltResponse(Object entity, int status, Class<?> entityClass) {
this.entity = entity;
this.entityClass = entityClass;
this.status = status;
}
@Override
public void setEntity(Object entity) {
if (entity == null) {
return;
}
if (entity.equals(this.entity)) {
return;
}
// reset entity true
this.resetEntity = true;
super.setEntity(entity);
}
public boolean isResetEntity() {
return resetEntity;
}
}

View File

@ -24,7 +24,6 @@ import org.apache.dubbo.rpc.protocol.rest.filter.RestResponseFilter;
import org.apache.dubbo.rpc.protocol.rest.filter.context.RestFilterContext;
import org.apache.dubbo.rpc.protocol.rest.netty.NettyHttpResponse;
import org.apache.dubbo.rpc.protocol.rest.request.RequestFacade;
import org.jboss.resteasy.specimpl.BuiltResponse;
import org.jboss.resteasy.spi.HttpResponse;
import javax.ws.rs.container.ContainerResponseFilter;
@ -50,16 +49,18 @@ public class ResteasyResponseContainerFilterAdapter implements RestResponseFilte
// response filter entity first
// empty jaxrsResponse
BuiltResponse jaxrsResponse = new BuiltResponse();
// build jaxrsResponse from rest netty response
DubboBuiltResponse dubboBuiltResponse = new DubboBuiltResponse(response.getResponseBody(), response.getStatus(), response.getEntityClass());
// NettyHttpResponse wrapper
HttpResponse httpResponse = new ResteasyNettyHttpResponse(response);
DubboContainerResponseContextImpl containerResponseContext = createContainerResponseContext(requestFacade, httpResponse, jaxrsResponse, containerRequestFilters.toArray(new ContainerResponseFilter[0]));
DubboContainerResponseContextImpl containerResponseContext = createContainerResponseContext(requestFacade, httpResponse, dubboBuiltResponse, containerRequestFilters.toArray(new ContainerResponseFilter[0]));
containerResponseContext.filter();
if (jaxrsResponse.getEntity() != null) {
// user reset entity
if (dubboBuiltResponse.hasEntity() && dubboBuiltResponse.isResetEntity()) {
// clean output stream data
restOutputStream(response);
writeResteasyResponse(url, requestFacade, response, jaxrsResponse);
writeResteasyResponse(url, requestFacade, response, dubboBuiltResponse);
}
addResponseHeaders(response, httpResponse.getOutputHeaders());

View File

@ -106,6 +106,9 @@ public class ServiceInvokeRestFilter implements RestRequestFilter {
// execute business method invoke
Result result = invoker.invoke(rpcInvocation);
// set raw response
nettyHttpResponse.setResponseBody(result.getValue());
if (result.hasException()) {
Throwable exception = result.getException();
logger.error("", exception.getMessage(), "", "dubbo rest protocol provider Invoker invoke error", exception);
@ -150,7 +153,8 @@ public class ServiceInvokeRestFilter implements RestRequestFilter {
public static void writeResult(NettyHttpResponse nettyHttpResponse, URL url, Object value, Class<?> returnType, MediaType mediaType) throws Exception {
MessageCodecResultPair booleanMediaTypePair = HttpMessageCodecManager.httpMessageEncode(nettyHttpResponse.getOutputStream(), value, url, mediaType, returnType);
// reset raw response result
nettyHttpResponse.setResponseBody(value);
nettyHttpResponse.addOutputHeaders(RestHeaderEnum.CONTENT_TYPE.getHeader(), booleanMediaTypePair.getMediaType().value);
}

View File

@ -113,7 +113,7 @@ public class NettyHttpHandler implements HttpHandler<NettyRequestFacade, NettyHt
/**
* execute response filters
* execute rest filters
*
* @param url
* @param requestFacade
@ -123,8 +123,8 @@ public class NettyHttpHandler implements HttpHandler<NettyRequestFacade, NettyHt
public void executeFilters(URL url, RequestFacade requestFacade, NettyHttpResponse nettyHttpResponse, ServiceDeployer serviceDeployer, List<RestFilter> restFilters) throws Exception {
RestFilterContext restFilterContext = new RestFilterContext(url, requestFacade, nettyHttpResponse, serviceDeployer);
for (RestFilter restResponseFilter : restFilters) {
restResponseFilter.filter(restFilterContext);
for (RestFilter restFilter : restFilters) {
restFilter.filter(restFilterContext);
if (restFilterContext.complete()) {
break;
}

View File

@ -54,6 +54,10 @@ public class NettyHttpResponse implements HttpResponse {
private boolean committed;
private boolean keepAlive;
private HttpMethod method;
// raw response body
private Object responseBody;
// raw response class
private Class<?> entityClass;
public NettyHttpResponse(final ChannelHandlerContext ctx, final boolean keepAlive) {
this(ctx, keepAlive, null);
@ -105,6 +109,7 @@ public class NettyHttpResponse implements HttpResponse {
@Override
public void sendError(int status, String message) throws IOException {
setStatus(status);
setResponseBody(message);
if (message != null) {
getOutputStream().write(message.getBytes(StandardCharsets.UTF_8));
}
@ -211,4 +216,21 @@ public class NettyHttpResponse implements HttpResponse {
}
}
public Object getResponseBody() {
return responseBody;
}
public void setResponseBody(Object responseBody) {
this.responseBody = responseBody;
if (responseBody != null) {
this.entityClass = responseBody.getClass();
}
}
public Class<?> getEntityClass() {
return entityClass;
}
}