spring boot实现超轻量级网关的方法(反向代理、转发)
在我们的rest服务中,需要暴露一个中间件的接口给用户,但是需要经过rest服务的认证,这是典型的网关使用场景。可以引入网关组件来搞定,但是引入zuul等中间件会增加系统复杂性,这里实现一个超轻量级的网关,只实现请求转发,认证等由rest服务的springsecurity来搞定。
如何进行请求转发呢?熟悉网络请求的同学应该很清楚,请求无非就是请求方式、HTTPheader,以及请求body,我们将这些信息取出来,透传给转发的url即可。
举例:
/graphdb/**转发到Graph_Server/**
获取转发目的地址:
privateStringcreateRedictUrl(HttpServletRequestrequest,StringrouteUrl,Stringprefix){ StringqueryString=request.getQueryString(); returnrouteUrl+request.getRequestURI().replace(prefix,"")+ (queryString!=null?"?"+queryString:""); }
解析请求头和内容
然后从request中提取出header、body等内容,构造一个RequestEntity,后续可以用RestTemplate来请求。
privateRequestEntitycreateRequestEntity(HttpServletRequestrequest,Stringurl)throwsURISyntaxException,IOException{ Stringmethod=request.getMethod(); HttpMethodhttpMethod=HttpMethod.resolve(method); MultiValueMapheaders=parseRequestHeader(request); byte[]body=parseRequestBody(request); returnnewRequestEntity<>(body,headers,httpMethod,newURI(url)); } privatebyte[]parseRequestBody(HttpServletRequestrequest)throwsIOException{ InputStreaminputStream=request.getInputStream(); returnStreamUtils.copyToByteArray(inputStream); } privateMultiValueMap parseRequestHeader(HttpServletRequestrequest){ HttpHeadersheaders=newHttpHeaders(); List headerNames=Collections.list(request.getHeaderNames()); for(StringheaderName:headerNames){ List headerValues=Collections.list(request.getHeaders(headerName)); for(StringheaderValue:headerValues){ headers.add(headerName,headerValue); } } returnheaders; }
透明转发
最后用RestTemplate来实现请求:
privateResponseEntityroute(RequestEntityrequestEntity){ RestTemplaterestTemplate=newRestTemplate(); returnrestTemplate.exchange(requestEntity,String.class); }
全部代码
以下是轻量级转发全部代码:
importorg.springframework.http.*; importorg.springframework.stereotype.Service; importorg.springframework.util.MultiValueMap; importorg.springframework.util.StreamUtils; importorg.springframework.web.client.RestTemplate; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; importjava.io.IOException; importjava.io.InputStream; importjava.net.URI; importjava.net.URISyntaxException; importjava.util.Collections; importjava.util.List; @Service publicclassRoutingDelegate{ publicResponseEntityredirect(HttpServletRequestrequest,HttpServletResponseresponse,StringrouteUrl,Stringprefix){ try{ //builduptheredirectURL StringredirectUrl=createRedictUrl(request,routeUrl,prefix); RequestEntityrequestEntity=createRequestEntity(request,redirectUrl); returnroute(requestEntity); }catch(Exceptione){ returnnewResponseEntity("REDIRECTERROR",HttpStatus.INTERNAL_SERVER_ERROR); } } privateStringcreateRedictUrl(HttpServletRequestrequest,StringrouteUrl,Stringprefix){ StringqueryString=request.getQueryString(); returnrouteUrl+request.getRequestURI().replace(prefix,"")+ (queryString!=null?"?"+queryString:""); } privateRequestEntitycreateRequestEntity(HttpServletRequestrequest,Stringurl)throwsURISyntaxException,IOException{ Stringmethod=request.getMethod(); HttpMethodhttpMethod=HttpMethod.resolve(method); MultiValueMap headers=parseRequestHeader(request); byte[]body=parseRequestBody(request); returnnewRequestEntity<>(body,headers,httpMethod,newURI(url)); } privateResponseEntity route(RequestEntityrequestEntity){ RestTemplaterestTemplate=newRestTemplate(); returnrestTemplate.exchange(requestEntity,String.class); } privatebyte[]parseRequestBody(HttpServletRequestrequest)throwsIOException{ InputStreaminputStream=request.getInputStream(); returnStreamUtils.copyToByteArray(inputStream); } privateMultiValueMap parseRequestHeader(HttpServletRequestrequest){ HttpHeadersheaders=newHttpHeaders(); List headerNames=Collections.list(request.getHeaderNames()); for(StringheaderName:headerNames){ List headerValues=Collections.list(request.getHeaders(headerName)); for(StringheaderValue:headerValues){ headers.add(headerName,headerValue); } } returnheaders; } }
Spring集成
SpringController,RequestMapping里把GET\POST\PUT\DELETE支持的请求带上,就能实现转发了。
@RestController @RequestMapping(GraphDBController.DELEGATE_PREFIX) @Api(value="GraphDB",tags={ "graphdb-Api" }) publicclassGraphDBController{ @Autowired GraphPropertiesgraphProperties; publicfinalstaticStringDELEGATE_PREFIX="/graphdb"; @Autowired privateRoutingDelegateroutingDelegate; @RequestMapping(value="/**",method={RequestMethod.GET,RequestMethod.POST,RequestMethod.PUT,RequestMethod.DELETE},produces=MediaType.TEXT_PLAIN_VALUE) publicResponseEntitycatchAll(HttpServletRequestrequest,HttpServletResponseresponse){ returnroutingDelegate.redirect(request,response,graphProperties.getGraphServer(),DELEGATE_PREFIX); } }
到此这篇关于springboot实现超轻量级网关(反向代理、转发)的文章就介绍到这了,更多相关springboot轻量级网关内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!