klxedu / blog

2 stars 0 forks source link

国网移动端接口网关调用方案 #44

Open songhuiqing88 opened 6 years ago

songhuiqing88 commented 6 years ago

场景说明

在国网项目中,由于在线学习应用的移动接口不能外网直接访问,外网访问必须通过国网网关。在网关中,允许访问的应用请求必须配置白名单,且必须每个接口都需要配置,且接口无状态。

产品移动接口调用方案

servlet实现示例(TODO部分需要项目实现)

package org.gtiles.solutions.partybuilding;

import java.io.IOException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
public class MobileDispatcherServlet extends HttpServlet {

    private static final long serialVersionUID = 80042407974663204L;

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doProcess(req, resp);
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doProcess(req, resp);
    }
    private void doProcess(HttpServletRequest request, HttpServletResponse response) throws ClientProtocolException, IOException {
        String encode = "UTF-8";
        //urlEncode 后的url
        String url = request.getParameter("url");
        //需要urlEncode ids=1&ids=2&name=宋慧青&age=12
        String serialParams = request.getParameter("serialParams");
        String loginID = request.getParameter("loginID");
        url = URLDecoder.decode(url, encode);
        //TODO 根据传入用户唯一标识获取用户,如果用户不存在,则返回用户不存在状态提示信息,存在则创建用户session
        //TODO 模拟设置用户SESSION
        request.getSession().setAttribute("_user_session_", loginID);
//      String url = "http://localhost:8080/gtiles/portal/test/a.json";
        HttpClient httpClient = HttpClientBuilder.create().build();
        HttpPost httpPost = new HttpPost(url);
        List<NameValuePair> list = new ArrayList<NameValuePair>();
        //设置请求参数
        if(serialParams!=null && !"".equals(serialParams)) {
            serialParams = URLDecoder.decode(serialParams, encode);
            for(String s : serialParams.split("&")) {
                String[] params = s.split("=");
                list.add(new BasicNameValuePair(params[0], params[1]));
            }
        }
        httpPost.setEntity(new UrlEncodedFormEntity(list,encode));
        //设置消息头的sessionID 保持session同步
        httpPost.setHeader("Cookie", "JSESSIONID="+request.getSession().getId());
        HttpResponse httpRes = httpClient.execute(httpPost);//执行请求
        String jsonResult = "{}";//设置统一无数据或异常数据返回格式
        if(httpRes!=null) {
            HttpEntity entity = httpRes.getEntity();
            if(entity != null){  
                jsonResult = EntityUtils.toString(entity,encode);//获取请求结果
            }  
        }
        response.setContentType("application/json;charset="+encode);//设置输出内容类型
        response.getWriter().write(jsonResult);
    }

}

web.xml配置,对应的请求需要免过滤

  <servlet>
    <servlet-name>mobileDispatcherServlet</servlet-name>
    <servlet-class>org.gtiles.solutions.partybuilding.MobileDispatcherServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>mobileDispatcherServlet</servlet-name>
    <url-pattern>/mobileDispatcherServlet</url-pattern>
  </servlet-mapping>
ssbunny commented 6 years ago
  1. 同一应用服务内,如果使用 HttpClient 请求自身,存在很大的回路风险,如果分离出两个应用服务,会增加维护成本及风险;

  2. 一次完整的请求需要通过手机webview调用门户原生插件(也是 HttpClient)发请求,通过网关反向代理,到app自己的应用服务器时,如再次通过 HttpClient 发请求,性能太差,既然已经是同一个服务,此方式远不如服务端转发(注:一定不能使用重定向,网络不通);

  3. 会议时已明确指出无 session ,如何 request.getSession().getId()

  4. 将所有移动接口配置为免过滤,配置规则为:/mobile/**

如何实现?

重点需要了解如何去除系统登录过程中的认证,以及我们改造登录后,如何直接使用系统的授权过程,以期达到最小的代码改动。统一转发问题已经处理。