1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 统一接口平台

统一接口平台

时间:2019-01-09 10:43:42

相关推荐

统一接口平台

1产品介绍

前端应用系统通过统一接口平台获取数据,不直接与外部系统接口打交道。统一接口平台通过多种方式与外部系统联接获取数据并向各前端应用系统提供各种数据格式包,将外部系统有效地隔离在业务系统之外。前端应用系统需要请求的外部接口需要在统一接口平台注册,开放。每次访问都会被有效的记录,实行监管。

2应用范围

前后端分离,跨域,缓存策略,接口管控,服务组装,负载均衡等。

3技术描述

应用包:servlet,ehcache,memcached/redis,http协议,http连接池,apache下httpclient,IOUtils,装饰模式,责任链模式,享元模式。

后台包:Spring MVC,Mybatis。

4架构描述

5设计欣赏

6项目工程

1.jdm-proxyadminweb:统一接口平台后台

2.jdm-proxyappweb:统一接口平台应用

3.jdm-proxycore:统一接口平台核心包

7使用手册

1.部署统一接口平台应用包到应用服务器。如部署了两台tomcat服务器,分别是192.168.1.1和192.168.1.2。

2.配置nginx反向代理,路由映射应用服务器地址。如:

upstream {

server 192.168.1.1:8080;

server 192.168.1.2:8080;

}

location /proxy/ {

proxy_pass ;

}

3.使用统一接口平台方法:路由地址+路由名称+p+接口地址,如:

/proxy/p/shop/checkUrl.json

4.相关服务接口地址都是在统一接口平台后台配置,通过推送xml文件到每台统一接口平台应用包所在的服务器。xml文件格式如下:

8核心代码

统一接口平台应用核心逻辑图:

一 ProxyServlet.java

get请求入口:

protectedvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{StringrequestId=UUID.randomUUID().toString();try{log.info("starttoproxyinit"+requestId);ProxyBeanproxy=newGetProxy(request,response,ProxyConfig.getInstance());proxy.setAttribute(ProxyConstants.PROXY_BEAN_ID,requestId);log.info("finishedtoproxyinit"+requestId);this.handleProxy(request,response,proxy);}catch(ProxyExceptione){e.printStackTrace();response.getWriter().println(e);}}

post请求入口:

protectedvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{StringrequestId=UUID.randomUUID().toString();try{log.info("starttoproxyinit"+requestId);ProxyBeanproxy=newPostProxy(request,response,ProxyConfig.getInstance());proxy.setAttribute(ProxyConstants.PROXY_BEAN_ID,requestId);log.info("finishedtoproxyinit"+requestId);this.handleProxy(request,response,proxy);}catch(ProxyExceptione){e.printStackTrace();response.getWriter().println(e);}}

put请求和delete请求类似,省略....

privatevoidhandleProxy(HttpServletRequestrequest,HttpServletResponseresponse,ProxyBeanproxy)throwsIOException{try{proxy.getFilterChain().doFilter(proxy);}catch(ProxyExceptione){e.printStackTrace();}catch(IOExceptione){e.printStackTrace();}finally{if(proxy!=null&&proxy.getHttpMethod()!=null){proxy.getHttpMethod().releaseConnection();}proxy.getFilterChain().clear();}}publicvoidinit(ServletConfigconfig)throwsServletException{super.init(config);ProxyConfig.getInstance().create();}

二 ProxyBean.java

相关成员变量和构造函数

privateMapcontext=newHashMap();privateProxyFilterChainfilterChain;privateHttpServletRequestrequest;privateHttpServletResponseresponse;privateHttpMethodhttpMethod;privateRequestBeanrequestBean;privateProxyConfigconfig;//postputhttp请求中来来自请求的输入字符串privateStringrequestString;//postputhttp请求中来来自请求的输入字符串//httpclient执行方法后,获取的响应流。//临时变量,方便其它过滤器重复使用。因为流只能使用一次,因此将其类为ByteArrayInputStreamprivateByteArrayInputStreamresultStream;publicProxyBean(HttpServletRequestrequest,HttpServletResponseresponse,ProxyConfigconfig)throwsProxyException{if(config==null||!config.isInitialized()){thrownewProxyException(HttpStatus.SC_INTERNAL_SERVER_ERROR,"Failedtoinittheproxyconfig");}this.request=request;this.response=response;this.config=config;this.doInit();}

获取url相关参数,并添加过滤器

protectedvoiddoInit()throwsProxyException{this.initPolicy();//初始化ProxyFilterChain,增加policy的proxyfilterListcustomFilters=newArrayList();ProxyFilterChainpfc=ProxyFilterChainFactory.getInstance().create(customFilters);this.filterChain=pfc;}privatevoidinitPolicy()throwsProxyException{StringmappingPath=request.getPathInfo();//接口服务方法名log.info("mappingPath==="+mappingPath);ServiceModelserviceModel=EhCache.getInstance(Constant.EHCACHE).get(Constant.PROXY_SERVICE,mappingPath);if(serviceModel==null){thrownewProxyException("theinterfaceservice:"+mappingPath+"doesnotexist");}StringtargetPath=serviceModel.getUrl();StringqueryString=request.getQueryString();//接口服务参数//过滤url中系统保留的paramif(queryString!=null){queryString=stripKnownParamters(queryString);}try{RequestBeanrequestBean=newRequestBean(targetPath+mappingPath,queryString);this.setRequestBean(requestBean);}catch(MalformedURLExceptione){e.printStackTrace();}}

最终执行请求

publicfinalvoiddoProxy()throwsProxyException,IOException{this.doBeforeProxy();this.doExecute();this.doAfterProxy();}

前置逻辑

protectedvoiddoBeforeProxy()throwsProxyException,IOException{//1.处理httpheaderEnumerationem=request.getHeaderNames();while(em.hasMoreElements()){StringheaderName=em.nextElement();StringheaderValue=request.getHeader(headerName);this.httpMethod.addRequestHeader(headerName,headerValue);}//2.处理httpcookiesif(request.getHeader("Cookie")!=null){StringrawCookiesString=request.getHeader("Cookie");if((rawCookiesString!=null)&&(rawCookiesString.length()!=0)){StringBuffercookieBuffer=newStringBuffer();String[]cookieParts=rawCookiesString.split(";");for(inti=0;i<cookieParts.length;i++){StringplainCookie=cookieParts[i].trim();Cookiecookie=newCookie(plainCookie);StringcookieName=cookie.getName();StringcookieValue=cookie.getValue();if(cookieBuffer.length()!=0){cookieBuffer.append(";");}cookieBuffer.append(cookieName).append("=").append(cookieValue);}System.out.println("Cookie="+cookieBuffer.toString());httpMethod.addRequestHeader("Cookie",cookieBuffer.toString());}}}

执行

publicfinalvoiddoExecute()throwsProxyException,IOException{longbefore=System.currentTimeMillis();intstatusCode=HttpStatus.SC_INTERNAL_SERVER_ERROR;try{statusCode=config.acquireHttpClient().executeMethod(httpMethod);StringmappingPath=request.getPathInfo();//将错误信息打印到日志,便于问题定位if(statusCode>=400){log.info("Faildtoexecutetheproxy,httpstatuscodeis"+statusCode+""+this.getRequestBean());}}catch(UnknownHostExceptione){statusCode=HttpStatus.SC_NOT_FOUND;thrownewProxyException(HttpStatus.SC_NOT_FOUND,"Thespecifiedtargethostisunknown!Thetargeturlis"+this.getRequestBean(),e);}catch(SocketExceptione){statusCode=HttpStatus.SC_NOT_FOUND;thrownewProxyException(HttpStatus.SC_NOT_FOUND,"Therewasanerrorconnectingtothetargetresource!Thetargeturlis"+this.getRequestBean(),e);}catch(SocketTimeoutExceptione){statusCode=HttpStatus.SC_REQUEST_TIMEOUT;thrownewProxyException(HttpStatus.SC_REQUEST_TIMEOUT,"Therewasatimeouterrorconnectingtothetargetresource!Thetargeturlis"+this.getRequestBean(),e);}catch(SSLHandshakeExceptione){statusCode=HttpStatus.SC_BAD_GATEWAY;thrownewProxyException(HttpStatus.SC_BAD_GATEWAY,"proxy_ui_ssl_certificate_not_trusted!Thetargeturlis"+this.getRequestBean(),e);}finally{longafter=System.currentTimeMillis();longexecuteTime=after-before;//如果执行时间过长,记录警告日志if(statusCode=ProxyConstants.PROXY_INVOKE_TIME_WARN_THRESHOLD){log.info("Theproxycostmstoexecute,it'stoolong."+this.getRequestBean());}//如果不是401和403的错误码,记录警告日志if(statusCode>=400&&statusCode!=401&&statusCode!=403){log.info("Faildtoexecutetheproxy,httpstatuscodeis"+statusCode+""+this.getRequestBean());}//保存http返回码到上下文中this.setAttribute(ProxyConstants.RESPONSE_STATUS_CODE,newInteger(statusCode));//将返回码结果保存在临时InputStream中,方便其它过滤器进行处理//在返回304的时候,Stream为nullif(httpMethod.getResponseBodyAsStream()!=null){this.setResultStream(newByteArrayInputStream(IOUtils.toByteArray(httpMethod.getResponseBodyAsStream())));}}}

后置逻辑

protectedvoiddoAfterProxy()throwsProxyException,IOException{//1.content-Type和gizpStringmappingPath=request.getPathInfo();ServiceModelserviceModel=EhCache.getInstance(Constant.EHCACHE).get(Constant.PROXY_SERVICE,mappingPath);if(serviceModel.getGzip().endsWith(Constant.GZIPY)){this.setAttribute(ProxyConstants.RESPONSE_GZIP_FLAG,Boolean.TRUE);}if(serviceModel.getContentType()!=null){this.setAttribute(ProxyConstants.RESPONSE_CONTENT_TYPE,serviceModel.getContentType());}//2.处理来自httpclient的responseheaderHeader[]headers=httpMethod.getResponseHeaders();for(inti=0;i<headers.length;i++){Headerheader=headers[i];if("Content-Type".equalsIgnoreCase(header.getName())||"Transfer-Encoding".equalsIgnoreCase(header.getName())){continue;}this.addResponseHeader(header.getName(),header.getValue());}}

三 ProxyFilterChainFactory.java

proxy filter chain的工厂类,负责实例化ProxyFilterChain

publicProxyFilterChaincreate(ListcustomFilters){Listfilters=newArrayList();//添加系统级的前置过滤器this.addProxyFilter(filters,ProxyInitFilter.class);this.addProxyFilter(filters,ValidationFilter.class);this.addProxyFilter(filters,BrowserCacheFilter.class);this.addProxyFilter(filters,AppCacheFilter.class);//添加用户级的自定义过滤器if(customFilters!=null){filters.addAll(customFilters);}//添加系统级的后置过滤器this.addProxyFilter(filters,ProxyExecuteFilter.class);returnnewProxyFilterChainImpl(filters);}privatevoidaddProxyFilter(Listfilters,Classclazz){try{ProxyFilterfilter=this.getFilter(clazz.getCanonicalName());if(filter==null){filter=(ProxyFilter)clazz.newInstance();//只有线程安全(单例)的proxyFilter才放到filter池中if(filter.isSingleton()){filterMap.put(clazz.getCanonicalName(),filter);}}filters.add(filter);}catch(IllegalAccessExceptione){}catch(InstantiationExceptione){}}

四 ProxyInitFilter.java

publicclassProxyInitFilterextendsAbstractProxyFilter{publicvoiddoFilter(ProxyBeanproxy,ProxyFilterChainfilterChain)throwsProxyException,IOException{HttpServletRequestrequest=proxy.getRequest();filterChain.doFilter(proxy);//设置responsecontent-TypeStringcontentType=(String)proxy.getAttribute(ProxyConstants.RESPONSE_CONTENT_TYPE);if(contentType!=null){proxy.getResponse().setContentType(contentType);}//设置http返回码IntegerstatusCode=(Integer)proxy.getAttribute(ProxyConstants.RESPONSE_STATUS_CODE);if(statusCode!=null){proxy.getResponse().setStatus(statusCode);if(proxy.getResultStream()!=null){IOUtils.copy(proxy.getResultStream(),proxy.getResponse().getOutputStream());}else{thrownewProxyException(HttpStatus.SC_INTERNAL_SERVER_ERROR,"Unabletogetproxyhttpresponsestatuscode.");}}}publicbooleanisSingleton(){returntrue;}}

五 ValidationFilter.java

publicclassValidationFilterextendsAbstractProxyFilter{publicvoiddoFilter(ProxyBeanproxy,ProxyFilterChainfilterChain)throwsProxyException,IOException{this.validateRequest(proxy);filterChain.doFilter(proxy);this.validateResponse(proxy);}privatevoidvalidateRequest(ProxyBeanproxy)throwsProxyException{HttpServletRequestrequest=proxy.getRequest();ServiceModelserviceModel=EhCache.getInstance(Constant.EHCACHE).get(Constant.PROXY_SERVICE,request.getPathInfo());StringrquestType=serviceModel.getMethod();String[]rqs=rquestType.split("\,");ListreqList=newArrayList();for(inti=0;i<rqs.length;i++){reqList.add(rqs[i]);}if(!reqList.contains(request.getMethod().toLowerCase())){thrownewProxyException(HttpStatus.SC_FORBIDDEN,request.getMethod()+"methodforproxyuri"+proxy.getRequestBean().toString()+"isnotallowed");}}privatevoidvalidateResponse(ProxyBeanproxy)throwsProxyException,IOException{//判断返回到mime-type是否合法HttpServletResponseresponse=proxy.getResponse();StringcontentType=(String)proxy.getAttribute(ProxyConstants.RESPONSE_CONTENT_TYPE);if(contentType!=null){if(true){response.sendError(HttpStatus.SC_FORBIDDEN,"TheresponseMIME-TYPEisnotallowed");return;}}}publicbooleanisSingleton(){returntrue;}}

六 BrowserCacheFilter.java

浏览器缓存

publicclassBrowserCacheFilterextendsAbstractProxyFilter{publicvoiddoFilter(ProxyBeanproxy,ProxyFilterChainfilterChain)throwsProxyException,IOException{filterChain.doFilter(proxy);IntegerstatusCode=(Integer)proxy.getAttribute(ProxyConstants.RESPONSE_STATUS_CODE);if((statusCode!=null&&statusCode==HttpStatus.SC_OK)&&(proxyinstanceofGetProxy)){try{//增加缓存设置intbroswer_inteval=3000;CacheControlcc=newCacheControl();cc.setMaxAge(broswer_inteval);proxy.getResponse().setHeader("Cache-Control",cc.toString());longexpires=System.currentTimeMillis()+broswer_inteval*1000;proxy.getResponse().setDateHeader("Expires",expires);}catch(Exceptionex){//出错不进行任何处理,不抛异常}}}publicbooleanisSingleton(){returntrue;}}

七 AppCacheFilter.java

应用层缓存,其中应用层缓存可以根据需要做一级缓存(本地缓存)和二级缓存(分布式缓存)publicvoiddoFilter(ProxyBeanproxy,ProxyFilterChainfilterChain)throwsProxyException,IOException{HttpServletRequestrequest=proxy.getRequest();BooleanisCache=false;//只有GET的情况下,才使用缓存if((proxyinstanceofGetProxy)&&isCache){proxy.setAttribute(ProxyConstants.APP_CACHE_ENABLE_KEY,Boolean.TRUE);Stringkey=proxy.getRequestBean().toString();//应用缓存的key指,采用proxy的URL//判断一级缓存CachedResponsecachedResponse=EhCache.getInstance(Constant.EHCACHE).get("proxy_response",key);if(cachedResponse==null){filterChain.doFilter(proxy);//只有返回码是200(成功),才将response的值保存到缓存中IntegerstatusCode=(Integer)proxy.getAttribute(ProxyConstants.RESPONSE_STATUS_CODE);if(statusCode!=null&&statusCode==HttpStatus.SC_OK){ListrespHeaders=(List)proxy.getAttribute(ProxyConstants.RESPONSE_KEADERS_KEY);StringcontentType=(String)proxy.getAttribute(ProxyConstants.RESPONSE_CONTENT_TYPE);cachedResponse=newCachedResponse(proxy.getResultStream(),respHeaders,contentType);//由于resultStream被copy一次,因此重新初始化到proxybean中proxy.setResultStream(cachedResponse.getRespInputStream());EhCache.getInstance(Constant.EHCACHE).set("proxy_response",key,cachedResponse);}}else{proxy.setResultStream(cachedResponse.getRespInputStream());proxy.setAttribute(ProxyConstants.RESPONSE_CONTENT_TYPE,cachedResponse.getContentType());//设置httpresponseheaderif(CollectionUtils.isNotEmpty(cachedResponse.getRespHeaders())){for(NameValuePairheader:cachedResponse.getRespHeaders()){proxy.getResponse().setHeader(header.getName(),header.getValue());}}//由于没有真正调用proxyhttp请求,因此认为此请求是成功的proxy.setAttribute(ProxyConstants.RESPONSE_STATUS_CODE,newInteger(HttpStatus.SC_OK));}}else{filterChain.doFilter(proxy);}}

八 ProxyExecuteFilter.java

publicclassProxyExecuteFilterextendsAbstractProxyFilter{publicvoiddoFilter(ProxyBeanproxy,ProxyFilterChainfilterChain)throwsProxyException,IOException{proxy.doProxy();}publicbooleanisSingleton(){returntrue;}}

调用的就是ProxyBean.java里面的实现

publicfinalvoiddoProxy()throwsProxyException,IOException{this.doBeforeProxy();this.doExecute();this.doAfterProxy();}

9后台演示地址

账号和密码在QQ群。

QQ群交流:124020918

10源码下载地址

QQ群下载:124020918

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。