Pit and solution of using OpenFeign in SpringBoot project

  • 2021-10-15 10:48:56
  • OfStack

1. Preface

Make a big hole in OpenFeign under SpringBoot project (note that it is not SpringCloud). Why not use Feign in SpringCloud?

First of all, my project is relatively simple (at present, only login and business module), so I won't introduce distributed architecture for the time being, but there are some connections between the two services, so I need to call the interface (I chose OpenFeign to realize this operation in many ways, and the road to stepping on the pit begins from now on...) .

2. Specific pits

When using OpenFeign, I directly refer to the official demo. The official example is written concisely and directly applied to my own project, and I can also make corresponding encapsulation and call it again. However, an feign core annotation @ RequestLine is used in demo, and the problem lies in this annotation.

At this time, if you use GET request, the requested interface will receive POST request, then A interface (requester) will report 500 error, and B interface (requester) will prompt that the interface does not support POST request (it is very normal not to support POST request, because method defined by B interface is GET method).

Here's a snippet of my code:

Custom UserFeign interface


public interface UserFeign { 
    /**
     *  According to userId Get user information 
     * @param userId
     * @return
     */
    @RequestLine("GET /user/getUserById?id={id}")
    Result getUserById(@Param("id") String userId);
}

Call the UserFeign interface


@Service
public class UserService{ 
    /**
     *  Pass OpenFegin Implementation interface call interface 
      * @param userId
     * @return
     */
    public Result getUserByIdWith(String userId) {
        UserFeign userInfo = Feign.builder()
                .decoder(new JacksonDecoder())
                .target(UserFeign.class, "http://localhost:8080");
        Result res = userInfo.getUserById(userId);
        return res;
    }
}

A Interface (Requestor)


@RequestMapping(value = "/test", method = RequestMethod.GET)
public Result test() {
    String id = "ad545461300a";
    return userService.getUserByIdWith(id);
}

B Interface (Requested Party)


@RequestMapping(value = "/getUserById", method = RequestMethod.GET)
public Result getUserByUserId(@RequestParam(required = true) String id){
    if ("".equals(id)) {
        throw new BusinessException(400, "userId Cannot be empty !");
    }
    Users info = usersService.getUserById(id);
    if (info == null) {
        throw new BusinessException(404, "userId Error !");
    }
    return ResultUntil.success(info);
}

I made a small tweak to the above code to encapsulate the methods in the calling UesrFeign interface in UserService and use @ service so I can inject UserService directly elsewhere and then call the methods in it.

You will find that the above code is no different from demo in official website, but the official document does not say that using @ RequestLine annotation needs to be configured (in fact, it needs to be configured).

The configuration code is as follows:


@Bean
public Contract useFeignAnnotations() {
    return new Contract.Default();
}

Complete the above configuration can be normal call, this problem has troubled me for several days today finally solved (really not easy), I hope this article is not written in vain.

Finally, I thank this article for finding a way of thinking when I give up. (The details encountered in debugging will not be repeated here)


Related articles: