apache / dubbo

The java implementation of Apache Dubbo. An RPC and microservice framework.
https://dubbo.apache.org/
Apache License 2.0
40.41k stars 26.41k forks source link

[Bug] How to get attachment data in the consumer ,attachment data set from provider cusome exception filter? #14416

Open GongLe opened 2 months ago

GongLe commented 2 months ago

Pre-check

Search before asking

Apache Dubbo Component

Java SDK (apache/dubbo)

Dubbo Version

3.2.14

Steps to reproduce this issue

How to get attachment data in the consumer ,attachment data set from provider cusome exception filter ? DubboProviderExceptionFilter: RpcContextAttachment serverContext = RpcContext.getServerContext(); serverContext.setObjectAttachment(ATTA_NAME_EXCEPTION_CODE, br.getCode()); DubboConsumerExceptionFilter: RpcContext.getServerContext().getObjectAttachments() ,RpcContext.getContext().getAttachments(); Neither method can be obtained

What you expected to happen

DubboProviderExceptionFilter set attachment data , DubboConsumerExceptionFilter get server attachment data ,used to customize exceptions extra data

Anything else

source code:

@Activate(group = CommonConstants.PROVIDER )
public class DubboProviderExceptionFilter implements Filter, Filter.Listener {
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
    public static String ATTA_NAME_EXCEPTION_CODE = "__code";
    public static String ATTA_NAME_EXCEPTION_DETAIL_MSG = "__detailMsg";
    public static String ATTA_NAME_EXCEPTION_DETAIL_DATA = "__data";

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        return invoker.invoke(invocation);
    }

    @Override
    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
        if (appResponse.hasException() && GenericService.class != invoker.getInterface()) {
            try {
                Throwable exception = appResponse.getException();

                String className = exception.getClass().getName();
                //如果是我们系统自定义异常直接返回
                if ( ClassUtil2.isAssignable(ServiceException.class, exception.getClass())) {
                    //服务提供方写入回传参数
                    ServiceException br = (ServiceException) exception;
                    invocation.setObjectAttachment(ATTA_NAME_EXCEPTION_CODE, br.getCode());
                    invocation.setObjectAttachment(ATTA_NAME_EXCEPTION_DETAIL_MSG, br.getDetailMsg());
                    invocation.setObjectAttachment(ATTA_NAME_EXCEPTION_DETAIL_DATA, br.getExtraData());

                    RpcContextAttachment serverContext = RpcContext.getServerContext();
                    serverContext.setObjectAttachment(ATTA_NAME_EXCEPTION_CODE, br.getCode());
                    serverContext.setObjectAttachment(ATTA_NAME_EXCEPTION_DETAIL_MSG, br.getDetailMsg());
                    serverContext.setObjectAttachment(ATTA_NAME_EXCEPTION_DETAIL_DATA, br.getExtraData());

                    return;
                }
@Activate(group = CommonConstants.CONSUMER )
public class DubboConsumerExceptionFilter implements Filter, Filter.Listener {

    @Override
    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
        Throwable exec = appResponse.getException();
        if (exec != null && ServiceException.class.isAssignableFrom(exec.getClass())) {
            Map<String, String> attachments = invocation.getAttachments();

            if (attachments.containsKey(ATTA_NAME_EXCEPTION_CODE)) {
                ReflectionUtil.setFieldValue(exec, "code", attachments.get(ATTA_NAME_EXCEPTION_CODE));
            }

            if (attachments.containsKey(ATTA_NAME_EXCEPTION_DETAIL_MSG)) {
                ReflectionUtil.setFieldValue(exec, "detailMsg", attachments.get(ATTA_NAME_EXCEPTION_DETAIL_MSG));
            }

            if (attachments.containsKey(ATTA_NAME_EXCEPTION_DETAIL_DATA)) {
                ReflectionUtil.setFieldValue(exec, "extraData", attachments.get(ATTA_NAME_EXCEPTION_DETAIL_DATA));
            }

        }
    }

Are you willing to submit a pull request to fix on your own?

Code of Conduct

wcy666103 commented 2 months ago

Reference here: https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/attachment/

It's not a Bug, it's just a logic problem with the built-in Filter in the framework in the higher version of dubbo, you're using it the wrong way.Please reference herer https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/attachment/#%E5%8E%86%E5%8F%B2%E9%81%97%E7%95%99%E9%97%AE%E9%A2%98

GongLe commented 2 months ago

Reference here: https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/attachment/

It's not a Bug, it's just a logic problem with the built-in Filter in the framework in the higher version of dubbo, you're using it the wrong way.Please reference herer https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/attachment/#%E5%8E%86%E5%8F%B2%E9%81%97%E7%95%99%E9%97%AE%E9%A2%98

Thanks for your reply! I don't understand,How to in consumer side filter get provider attachments data , current provider data is available outside the method. “ServerContext:在 Client 端和 Server 端使用,用于从 Server 端回传 Client 端使用,Server 端写入到 ServerContext 的参数在调用结束后可以在 Client 端的 ServerContext 获取到”

GongLe commented 2 months ago

Reference here: https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/attachment/ It's not a Bug, it's just a logic problem with the built-in Filter in the framework in the higher version of dubbo, you're using it the wrong way.Please reference herer https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/attachment/#%E5%8E%86%E5%8F%B2%E9%81%97%E7%95%99%E9%97%AE%E9%A2%98

Thanks for your reply! I don't understand,How to in consumer side filter get provider attachments data , current provider data is available outside the method. “ServerContext:在 Client 端和 Server 端使用,用于从 Server 端回传 Client 端使用,Server 端写入到 ServerContext 的参数在调用结束后可以在 Client 端的 ServerContext 获取到”

After consumer side filter DubboConsumerExceptionFilter#invoke method ,Still get no data!

  @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { 
        Result invoke = invoker.invoke(invocation);
        if(invoke.hasException()) {
           //.....  get provider attachments data 
        }
        return invoke;
    }
EarthChen commented 2 months ago

It is not recommended to use obj as Attachment. For some protocols, only some basic types may be supported.

GongLe commented 2 months ago

Test on consumer filter set attachment data ,use RpcContext.getClientAttachment().setAttachment api can be transfer to provider filter, use api RpcContext.getServerAttachment().getObjectAttachments()

GongLe commented 2 months ago

Actually,It's logic bug ! on the default ConsumerContextFilter onResponse method, will be set clientResponseContext attachments , But custom consumer filter onResponse method always execute the default first

org.apache.dubbo.rpc.cluster.filter.support.ConsumerContextFilter#onResponse

3d9479205b0e3ed2c366b6302fa5ba28

GongLe commented 2 months ago

another question,dubbo 3.0 how to define filter like this config :

wcy666103 commented 2 months ago

Can you provide a working program?