These are chat archives for spring-cloud/spring-cloud

10th
Aug 2016
bitsofinfo
@bitsofinfo
Aug 10 2016 00:07

So I am experiencing this little monster:

"A ServletContext is required to configure default servlet handling"

http://stackoverflow.com/questions/23638462/how-do-i-add-method-based-security-to-a-spring-boot-project

I've read several Stack overflow articles and indeed it seems to be related to @EnableGlobalMethodSecurity and I am declaring a custom PermissionEvaluator (in a separate config class). That is all fine.

However once I try to @Autowired a Feign client instance into the config class so I can wire it into my custom PermissionEvaluator I get this servletcontext error.

WORKS

@Configuration
public class MethodSecurityConfig  {
    @Bean
    protected PermissionEvaluator myPermissionEvaluator() {
        return new MyPermissionEvaluator(null);
    }
}

BLOWS UP with "A ServletContext is required to configure default servlet handling"

@Configuration
public class MethodSecurityConfig  {

    @Autowired
    private MyFeignClient myFeignClient;

    @Bean
    protected PermissionEvaluator myPermissionEvaluator() {
        return new MyPermissionEvaluator(myFeignClient);
    }
}

Spent many hours on this and really could use some pointers. Thanks!

Ryan Baxter
@ryanjbaxter
Aug 10 2016 00:28
@bitsofinfo unfortunately I dont have any useful advice for you (still the n00b of the team), but if you open and issue and provide an example I am sure we can look into it
Spencer Gibb
@spencergibb
Aug 10 2016 00:29
The autowired client is causing some early instantiation. Can you not use the feign client? Probably not what you want to hear. Maybe @Lazy?
bitsofinfo
@bitsofinfo
Aug 10 2016 00:30
Hah! I just tried that before you posted, and yes that fixes it on the feign bean
thanks though. I must say I've had this "servletcontext" error pop up a few times now and its really one of the more frustrating ones to figure out, a big time eater that induces a lot of trial and error debugging. I wonder if there is a better way to get more relevant info in such scenarios
Spencer Gibb
@spencergibb
Aug 10 2016 00:33
Maybe
Mike Liu
@mikexliu
Aug 10 2016 03:13
@spencergibb Sorry to backtrack, but did you see my question about ClientFactory? August 8 @ 22:53
Jose Armesto
@fiunchinho
Aug 10 2016 13:49
using Zuul, is it possible to match requests using subdomains instead of paths?
all examples I see use paths to match
Spencer Gibb
@spencergibb
Aug 10 2016 14:07
Not yet, there is an open issue
Jose Armesto
@fiunchinho
Aug 10 2016 14:40
do you have a link? I can't find it :/
julsteele
@julsteele
Aug 10 2016 16:08
@marcingrzejszczak we have extended the Cleint for feign : public class MicroserviceFeignClient extends Client.Default { ..@Override
public Response execute(Request request, Request.Options options) throws IOException {..} }...and injected that @Bean public Client client() {
return new MicroserviceFeignClient(null, null); }..but at runtime the Client used its still the Client.Default client intance.
Using the postprocessor does not help to get it done also: public class MicroserviceFeignClientPostProcessor implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof Client.Default) { if (!(bean instanceof MicroserviceFeignClient)) { return new MicroserviceFeignClient((Client.Default) bean); } } if (bean instanceof FeignClientsConfiguration) { ((FeignClientsConfiguration) bean).feignBuilder().client(new MicroserviceFeignClient(null, null)); return bean; } return bean; }
Spencer Gibb
@spencergibb
Aug 10 2016 16:19
@mikexliu which communication medium was that on?
julsteele
@julsteele
Aug 10 2016 16:22
@spencergibb How can we overwite the execute Method of the Client used in Feign - we want to intercept the response. It look like the Feign Client used is crreated from "SpringClientFactory" that doesn't care for the @Bean Client client() injected into the Feign Configuration
Spencer Gibb
@spencergibb
Aug 10 2016 16:23
"we want to intercept the response”. why?
julsteele
@julsteele
Aug 10 2016 16:28
because we want to intercept responses with status 200 and a specific application type. These contain exceptions we want to unwrap on the client side.
We want to serilaize business errors as 200er instead of 400er (error code wrapped into body)..an rethrow the 200er errors as same Exception of client
4oo er are caught in hytrix fallback and we don't want these to get into the circuit braker
Thibaud Lepretre
@kakawait
Aug 10 2016 16:31
By using Zuul if we are defining route with plain old url like zuul.routes.<service>.url=http://foo.bar (with Eureka enabled), we will use SimpleHostRoutingFilter instead of RibbonRoutingFilter. Nevertheless it seems that RibbonRoutingFilter in addition to service discovery also wrap request inside HystrixCommand. So SimpleHostRoutingFilter seems to no take advantage of circuit breaking capability (as it said on documentation). But the real question is there is any reason to do not add circuit breaking capability for such case?
Spencer Gibb
@spencergibb
Aug 10 2016 16:32
@julsteele if using a custom Client doesn’t work that is a bug.
@kakawait no
julsteele
@julsteele
Aug 10 2016 16:33
@spencergibb is there a bug ticket already?
Spencer Gibb
@spencergibb
Aug 10 2016 16:34
not that I know of. Please provide steps to reproduce or a minimal project that does.
Thibaud Lepretre
@kakawait
Aug 10 2016 16:35
because I'm trying to develop new filter to support url like http://<service>/ à la RestTemplate (loadbalanced). So I'm asking myself if I have to write something new maybe I could include same behavior for any cases:
  1. using serviceId
  2. using plain old url
  3. using url with serviceId as hostname
  4. using url with serviceId as hostname using listOfServers static config (Eurekadisabled)
all should be circuit breaking capable
julsteele
@julsteele
Aug 10 2016 16:37
@spencergibb Okay.
Is there another way to get to the Response object as a workaround?
Spencer Gibb
@spencergibb
Aug 10 2016 16:37
you can return ResponseEntity
julsteele
@julsteele
Aug 10 2016 16:41
we are using ResponseEntity wrapping the exception in the exceptionHandler on server side.
On client side we have a custom error handler. This is able to unwrap the exception. However, this only works for status code 4x and 5xx (which both are caught by hystrix).
So our main question is - how do we intercept 200 status code responses on a feign client?
Fabian Wallwitz
@cforce
Aug 10 2016 17:10
..or how to catch any 400er in errordecoder but not in fallback
Spencer Gibb
@spencergibb
Aug 10 2016 17:15
@julsteele Client is still the right place
Marcin Grzejszczak
@marcingrzejszczak
Aug 10 2016 18:34
@julsteele this might be the ordering issue (I thought that I replied)
Maybe first the tracing client is registered
Try registering your with greater order
Hmm I think that I mixed channels
I thought it's a Sleuth one :D
Just follow what @spencergibb said and ignore me :)
Fabian Wallwitz
@cforce
Aug 10 2016 18:37
;(..so registering with hifher order dors not help ?
well spencer says its not possible currently 😂
@marcingrzejszczak I tried to use your code ..but unable to inject my own client
at the end SpringClientFactory uses the RibbonLbClient instead
Marcin Grzejszczak
@marcingrzejszczak
Aug 10 2016 18:41
So it's a bug - file an issue and steps to reproduce
Spencer Gibb
@spencergibb
Aug 10 2016 18:45
@cforce are you talking about a ribbon load balancing client or feign Client?
Fabian Wallwitz
@cforce
Aug 10 2016 18:56
I want to intercept the client inside FeignClient..however at runtime it look like The SpringClientFactory instantiates a RibbonLbClient extending the Client.Default. whereas my @Bean Client client () { ..return MyClient extends Client.Default () } has no effect
Mike Liu
@mikexliu
Aug 10 2016 18:58
@cforce i have a similar issue. Where is your @Bean ?
Spencer Gibb
@spencergibb
Aug 10 2016 18:58
SpringClientFactory deals with ribbon not feign. It doesn’t create a feign Client.
Fabian Wallwitz
@cforce
Aug 10 2016 19:03
@mikexliu its in the @Configuration FeignClientConfiguration i use at the @FeignClient (configuration=FeignClientConfiguration.class)
@spencergibb well ..but that is what happens..i ???
Mike Liu
@mikexliu
Aug 10 2016 19:05
The docs say you should put a Feign.Builder to be injected, not Client. (That's actually the issue I have; using the Feign.Builder doesn't seem to work)
(unless i'm not reading it right)
(i'm still new to all this stuff :D)
Spencer Gibb
@spencergibb
Aug 10 2016 19:06
@cforce without seeing a sample I can’t tell. SpringClientFactory knows nothing about feign.
Fabian Wallwitz
@cforce
Aug 10 2016 19:07
I also tried to use the builder..as you said ..does not work too
Mike Liu
@mikexliu
Aug 10 2016 19:08
@spencergibb I've been trying to step through the code to see why Feign.Builder isn't being used by the Configuration defined by @FeignClient. Any ideas?
Spencer Gibb
@spencergibb
Aug 10 2016 19:08
We have tests for custom builders. So if you can provide a project that recreates the problem we can take a look.
Mike Liu
@mikexliu
Aug 10 2016 19:10
I'll see if I can create a test that fails..
Spencer Gibb
@spencergibb
Aug 10 2016 19:10
thanks
Mike Liu
@mikexliu
Aug 10 2016 19:25
@spencergibb can you see if I created this test case properly? mikexliu/spring-cloud-netflix@0d11095 (it fails)
@spencergibb sorry, i also just saw your mention from way earlier. I was referring to my chat here in gitter. Specifically:
@mikexliu
Hi, does anyone know why @EnableFeignClients does not register its LoadBalancers into ClientFactory.java?

@spencergibb
@mikexliu which ClientFactory?

@mikexliu
@spencergibb Referring to https://github.com/Netflix/ribbon/blob/master/ribbon-loadbalancer/src/main/java/com/netflix/client/ClientFactory.java . I'm not sure if this is the right channel for the question either.
Fabian Wallwitz
@cforce
Aug 10 2016 19:29
@mikexliu
Spencer Gibb
@spencergibb
Aug 10 2016 19:32
@mikexliu we use a SpringClientFactory that loads things from the spring context rather than instantiating beans via reflection.
Spencer Gibb
@spencergibb
Aug 10 2016 19:43

@mikexliu the following works for me

    @Bean
    public Client feignClient() {
        return new MyClient();
    }

instead of a builder that sets the client, because the client will get set later on your custom builder.

Mike Liu
@mikexliu
Aug 10 2016 19:53

@spencergibb thanks! Got it working now. I forgot to inject the SpringClientFactory. Needed to be like:

@Bean
    public Client feignClient(final CachingSpringLoadBalancerFactory cachingFactory, final SpringClientFactory clientFactory) {
}

and everything worked. @cforce maybe this is the same issue you're having?

yeah, just confirmed again. does work :)
Spencer Gibb
@spencergibb
Aug 10 2016 19:58
Nice. Customizations to a Builder bean will get overridden later.
Marcin Grzejszczak
@marcingrzejszczak
Aug 10 2016 19:59
Good idea!!
Mike Liu
@mikexliu
Aug 10 2016 19:59
Yeah that makes 100% sense. I think the documentation wasn't clear exactly what can be found in the Configuration. It only lists: Logger.Level, Retryer, ErrorDecoder, Requestion.Options, Collection<RequestInterceptor>
Sorry, being nitpicky. The fact that Contract was listed with Feign.Builder made it seem like Builder could be marked as a @Bean.
Spencer Gibb
@spencergibb
Aug 10 2016 20:00
They are all listed, your list is the list that doesn’t have default beans
Fabian Wallwitz
@cforce
Aug 10 2016 20:00
Omg ..saved my day /night
Tx!!
Plz update the spec
/doc
Mike Liu
@mikexliu
Aug 10 2016 20:04
@spencergibb Sorry, I guess it's only missing Client in the list.
Spencer Gibb
@spencergibb
Aug 10 2016 20:04
"Plz update the spec” to what?
I see
Mike Liu
@mikexliu
Aug 10 2016 20:11

I think adding something like:
Client feignClient LoadBalancerFeignClient

  • Requires it to be in the form of
    @Bean
    public Client client(CachingSpringLoadBalancerFactory cachingFactory, SpringClientFactory clientFactory) {
    return new LoadBalancerFeignClient(..., cachingFactory, clientFactory);
    }

Let me know if that makes sense. I had kept trying to return new Client.Default(trustAllSocketFactory, trustAllHostnames) without success

bitsofinfo
@bitsofinfo
Aug 10 2016 21:36
I have a @FeignClient that is passing a GET parameter w/ a @ symbol in it, the endpoint is reporting that it received the @ as a %2540 (which means something is double escaping this). The character is a @ before it enters the feign client, but the response from the called service comes back with an error that my data could not be found because what it received was %2540... where should I start looking....
bitsofinfo
@bitsofinfo
Aug 10 2016 21:48
When debugging, when my value (that is pre encoded by something higher up in the feign/ribbon layer) in the url (i.e. ...&email=some%40emailaddr.com)
enters this method at: org.springframework.cloud.netflix.feign.ribbon.FeignLoadBalancer.reconstructURIWithServer it hits this line of code:
UriComponentsBuilder.fromUri(original).scheme("https").build().toUri(); which re-encodes the value so I now have ...&email=some%2540emailaddr.com in the final url that is being executed
Again, when this parameter is passed to my @FiegnClient annotated interface method, it is not-encoded, the value is some@emailaddr.com
my interface declaration looks like this:
@FeignClient(name="my-endpoint", fallback = UserClientFallback.class)
public interface UserClient {

    @RequestMapping(method = RequestMethod.GET, value = "/users/search/findByEmail?projection=minimal", consumes = "application/json")
    public Object findByEmail(@RequestParam("email") String email);
}
Spencer Gibb
@spencergibb
Aug 10 2016 21:51
just fixed a similar issue here spring-cloud/spring-cloud-netflix#1241
open an issue? PR’s welcome. off to dinner
bitsofinfo
@bitsofinfo
Aug 10 2016 22:01
spring-cloud/spring-cloud-netflix#1245