Spring Cloud Learning (6)-Zuul micro-service Gateway

Source: Internet
Author: User
Tags base64

MicroServices architecture, usually a business system will have a lot of microservices, such as: OrderService, Productservice, UserService ..., in order to make the invocation more simple, usually in the front end of these services to encapsulate a layer, similar to the following:

In front of this layer is commonly known as "Gateway layer", its existence significance is that the "1 to N" problem into the "1 to 1" problem, while the request to the real micro-service, can do some preprocessing, such as: source legality detection, authorization check, anti-crawler and so on ...

In the traditional way, the most Earth-like approach, the gateway layer can be encapsulated in human flesh, similar to the following sample code:

Loginresult Login (...) {
TODO preprocessing ... return Userservice.login ();//Call the User Service's login method }product queryproduct (...) {
TODO preprocessing ... return productservice.queryproduct ();//Invoke the Query method of the product service }order submitorder (...) {
TODO preprocessing ... return Orderservice.submitorder ();//Call the Order service's Query method}

To do this, of course, can run, but the maintenance of a large amount, the subsequent micro-services to add new methods, all need to manually add the appropriate method package at the gateway layer, and Spring cloud Zuul is a good solution to this problem, as follows:

Zuul as gateway layer, itself is a micro-service, with other services service-1,service-2, ... Like Service-n, are registered on the Eureka server, you can discover each other, Zuul can perceive which services are online, and by configuring routing rules (shown later), you can automatically forward the request to the specified back-end microservices, for some common preprocessing (such as: Permission authentication , token legitimacy check, gray-level verification, some traffic guidance, etc.), can be placed in the so-called filter (zuulfilter) processing, so that the backend service after the new service, Zuul layer almost no modification.

Steps to use:

One, add Zuul-dependent jar packages

Compile ' Org.springframework.cloud:spring-cloud-starter-zuul '

Ii. Configuring routing in Application.yml

Zuul:  routes:    api-a:      path:/api-user/**      service-id:service-provider      sensitive-headers:    Api-b:      path:/api-order/**      Service-id:service-consumer

Explanation: The above configuration indicates that the URL request that/api-user/begins will be forwarded to the Service-provider,/api-order/URL request, will be forwarded to service-consumer this micro-service.

Third, the fuse treatment

If the microservices behind the gateway are hung, Zuul also allows you to define a fallback class for fusing, referring to the following code:

Package Com.cnblogs.yjmyzz.spring.cloud.study.gateway;import Org.springframework.cloud.netflix.zuul.filters.route.zuulfallbackprovider;import Org.springframework.http.httpheaders;import Org.springframework.http.httpstatus;import Org.springframework.http.mediatype;import Org.springframework.http.client.clienthttpresponse;import Org.springframework.stereotype.component;import Java.io.bytearrayinputstream;import Java.io.IOException;import Java.io.inputstream;import java.nio.charset.charset;/** * Created by yangjunming on 2017/7/14. */@Componentpublic class Serviceconsumerfallbackprovider implements Zuulfallbackprovider {@Override public String g    Etroute () {return "Service-consumer"; } @Override Public Clienthttpresponse fallbackresponse () {return new Clienthttpresponse () {@Over            Ride public Httpstatus Getstatuscode () throws IOException {return httpstatus.ok; } @Override public int GetrawstAtuscode () throws IOException {return This.getstatuscode (). value (); } @Override Public String Getstatustext () throws IOException {return THIS.GETSTATUSC            Ode (). Getreasonphrase (); } @Override public void Close () {} @Override public InputStream ge            TBody () throws IOException {return new Bytearrayinputstream ("Service-consumer not Available". GetBytes ()); } @Override Public Httpheaders getheaders () {httpheaders headers = new Httpheaders (                );                MEDIATYPE MT = new MediaType ("Application", "JSON", Charset.forname ("UTF-8"));                Headers.setcontenttype (MT);            return headers;    }        }; }}

Developers simply specify the microservices instance to be processed in the Getroute method and rewrite the fallbackresponse.

At this point, if you observe the/health endpoint, you can also see that the hystrix is in a melt-off state

Four, Zuulfilter filter

Filters are a very useful mechanism, following several classic scenarios under the demo:

4.1.Token verification/Safety Certification

When the gateway is exposed directly to the public network, the terminal will call a service, usually send the token after login, the gateway layer to verify token validity, if the token is invalid (or not token), prompt to re-login or direct rejection. In addition, the microservices behind the gateway, if you set up basic Auth in spring security (that is, do not allow anonymous access, you must provide a user name, password), or you can handle it in filter. Refer to the following code:

Package Com.cnblogs.yjmyzz.spring.cloud.study.gateway;import Com.netflix.zuul.zuulfilter;import Com.netflix.zuul.context.requestcontext;import Org.apache.commons.codec.binary.base64;import Org.slf4j.Logger; Import Org.slf4j.loggerfactory;import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; Import Org.springframework.stereotype.component;import javax.servlet.http.httpservletrequest;/** * Created by Yangjunming on 2017/7/13. */@Componentpublic class Accessfilter extends Zuulfilter {private static Logger Logger = Loggerfactory.getlogger (Acces    Sfilter.class);    @Override public String FilterType () {return filterconstants.pre_type;    } @Override public int filterorder () {return 0;    } @Override public Boolean shouldfilter () {return true;        } @Override public Object run () {RequestContext CTX = Requestcontext.getcurrentcontext ();        HttpServletRequest request = Ctx.getrequest (); Object token = RequeSt.getparameter ("token");            Check token if (token = = null) {Logger.info ("token is empty, no access allowed!");            Ctx.setsendzuulresponse (FALSE);            Ctx.setresponsestatuscode (401);        return null; } else {//todo obtains the corresponding login information according to token, verifies (slightly)}//Adds basic Auth authentication information Ctx.addzuulrequestheader ("Au        Thorization "," Basic "+ getbase64credentials (" App01 "," * * * * "));    return null; } private string Getbase64credentials (string username, string password) {string plaincreds = Username + ":" + P        Assword;        byte[] plaincredsbytes = Plaincreds.getbytes ();        byte[] base64credsbytes = base64.encodebase64 (plaincredsbytes);    return new String (base64credsbytes); }}

There are 4 types of filter, whose constant values are defined in org.springframework.cloud.netflix.zuul.filters.support.FilterConstants

Zuul Filter Type Constants-----------------------------------/** * {@link zuulfilter#filtertype ()} error type. */string Error_type = "ERROR";/** * {@link zuulfilter#filtertype ()} post TYPE. */string Post_type = "POST";/** * {@link zuulfilter#filtertype ()} Pre TYPE. */string Pre_type = "PRE";/** * {@link zuulfilter#filtertype ()} Route TYPE. */string Route_type = "ROUTE";

Security checks are generally placed before the request is actually processed, so the above example FilterType is specified as the pre, and the rest is simply to rewrite their logic in the Shouldfilter (), run () method.

4.2 Dynamically modifying request parameters

Zuulfilter can intercept all request parameters, and modify it, such as: Terminal sent data, for security requirements, may be encrypted processing, the gateway layer to decrypt the parameters, and then pass to the back of the service, such as: the user passed the token value, need to convert to UserID /username this information and then pass it on to the micro service behind it. Refer to the following run method:

    Public Object Run () {try {RequestContext context = Getcurrentcontext ();            InputStream in = (InputStream) context.get ("requestentity");            if (in = = null) {in = Context.getrequest (). getInputStream ();            The String BODY = streamutils.copytostring (in, Charset.forname ("UTF-8"));            BODY = "Dynamically add a piece of content to the body:" + body;            byte[] bytes = body.getbytes ("UTF-8");                Context.setrequest (New Httpservletrequestwrapper (Getcurrentcontext (). Getrequest ()) {@Override Public ServletInputStream getInputStream () throws IOException {return new Servletinputstreamwrapper                (bytes);                } @Override public int getcontentlength () {return bytes.length; } @Override public Long Getcontentlengthlong () {return Bytes.len                Gth            }});        } catch (IOException e) {rethrowruntimeexception (e);    } return null; }

For more examples of filter, you can refer to the official website: https://github.com/spring-cloud-samples/sample-zuul-filters

4.3 grayscale release (Gated Launch/gray release)

In large-scale distributed system, gray-scale publishing is an important means to ensure the safety of the online system, the general practice is: from the cluster to designate a (or a few) machines, each time to do a new release before the release of these machines, first to see if it is normal, if stable operation, and then released to other machines. This strategy, which is equivalent to grayscale by a subset of nodes, can meet the requirements in most cases, but there are some specific scenarios that might not be appropriate.

For example: The author is located in the "Delicious do not Wait" company, the main B-end users for the food and beverage brands of businesses, most of the case, if the new on a function, hoping to find some small-scale restaurant to do the pilot, first look at the running after the line, if run well, and then promote to other businesses.

Another example: There are more than n versions of the backend service running concurrently, such as V1, V2, now added a V3 version (which is very common in mobile app), I hope that only partially upgraded the app's users access to the latest V3 version of the service, other users still access the old version, after the system stability, Further large-scale prompting users to upgrade.

The nature of these grayscale requirements, which appear to vary in demand, is essentially the same: turning the request (based on the parameter content + business rules) to a specific grayscale machine. Spring Cloud Microservice has a metadata-map ( metadata ) setting that can be used to meet such needs.

The first thing to do is introduce a jar package: (This is an open source project on GitHub Ribbon-discovery-filter-spring-cloud-starter)

Compile ' io.jmnarloch:ribbon-discovery-filter-spring-cloud-starter:2.1.0 '

Examples are as follows:

Set the following metadata-map in the application.yml of each service

Eureka:  instance:    metadata-map:      gated-launch:false

That is, when all nodes are published, the default grayscale mode is False. The configuration on a particular grayscale machine is then changed to True (indicating that the machine is used for grayscale verification).

Then refer to the following code in Zuulfilter:

    @Override public Object Run () {RequestContext CTX = Requestcontext.getcurrentcontext ();        HttpServletRequest request = Ctx.getrequest ();        Object token = request.getparameter ("token");            Check token if (token = = null) {Logger.info ("token is empty, no access allowed!");            Ctx.setsendzuulresponse (FALSE);            Ctx.setresponsestatuscode (401);        return null; } else {//todo Gets the appropriate login information based on token and checks (slightly)//Grayscale Example Ribbonfiltercontextholder.clearcurrentcon            Text (); if (Token.equals ("1234567890")) {Ribbonfiltercontextholder.getcurrentcontext (). Add ("Gated-launch", "true")            ;            } else {Ribbonfiltercontextholder.getcurrentcontext (). Add ("Gated-launch", "false"); }}//Add basic AUTH Certification Information Ctx.addzuulrequestheader ("Authorization", "Basic" + getbase64credentials ("app        01 "," * * * * "));    return null; }

Note 18-23 lines, which demonstrate that the request is directed to the Gated-lanuch=true machine via a specific token parameter value. (Note: Refer to this principle, you can put the parameter value, change their version-version number, shopid-merchant ID, etc.). This request is forwarded to the grayscale node as long as the token=1234567890 in the request parameter.

If a friend is curious about how this can be done, look at the Io.jmnarloch.spring.cloud.ribbon.predicate.MetadataAwarePredicate class:

    @Override    protected Boolean apply (Discoveryenabledserver server) {        final Ribbonfiltercontext context = Ribbonfiltercontextholder.getcurrentcontext ();        Final set<map.entry<string, string>> attributes = Collections.unmodifiableset (Context.getattributes (). EntrySet ());        Final map<string, string> metadata = Server.getinstanceinfo (). GetMetaData ();        Return Metadata.entryset (). Containsall (attributes);    }

The general principle is that in context, the developer-set properties are compared to the Metadata-map in the service node, and if the METADATA-MAP includes developer-set properties, it returns success (that is, selecting this server)

Sample Source: Https://github.com/yjmyzz/spring-cloud-demo

Spring Cloud Learning (6)-Zuul micro-service Gateway

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.