Java自定义开发义反向代理

功能描述

需要代理superMap iServer服务及各个系统公布接口,需要做访问限制,申请然后生成key,进行验证才可以正常使用接口,代理的服务需要提前在数据库注册,并生成代理地址,给使用者代理地址,在后台根据代理地址携带信息查询到原地址进行请求,建议使用Redis缓存数据库保存地址数据及访问量,提高代理速度

1.包引入

<dependency>
	<groupId>org.apache.httpcomponents</groupId>
	<artifactId>httpclient</artifactId>
</dependency>

2.二三维原地址及代理地址生成格式

二维
原地址:http://199.215.110.119:8090/iserver/services/map-JN/rest/maps/综合交通规划
代理地址:http://127.0.0.1:8010/map/37
三维
原地址:http://199.215.110.119:8040/iserver/services/3D/rest/realspace/datas/绿化
代理地址:http://127.0.0.1:8010/scene/38/rest/realspace/config
注意
二维可以在代理地址后面拼接参数,但是三维不可以,需要使用以下代码调用

viewer.scene.addS3MTilesLayerByScp(
 	  "http://127.0.0.1:8010/scene/38/rest/realspace/config", {
      name: '绿化',
      customRequestHeaders:{
          key:'您的应用key',
          // 参数......
      }
  })

3.代理服务代码

/**
 * 需要在安全框架下允许访问此接口
 */
import com.tydt.common.utils.ProxyServiceUtils;
import com.tydt.common.utils.StringUtils;
import com.tydt.project.web.service.domain.ProxyService;
import com.tydt.project.web.service.service.IProxyServiceService;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;

@Controller
@RequestMapping
@CrossOrigin
public class SuperMapProxyController {

    @Autowired
    private IProxyServiceService proxyService;

    /**
     * 代理三维服务
     * @param request
     * @param response
     */
    @RequestMapping(value = "/scene/**",method = {RequestMethod.OPTIONS,RequestMethod.POST,RequestMethod.GET})
    public void sceneProxy(HttpServletRequest request, HttpServletResponse response){
        String method = request.getMethod();
        String key = request.getHeader("key");
        try {
            if("GET".equals(method)){
                this.doSceneGet(request,response,key);
            }else {
                this.doScenePost(request,response,key);
            }
        } catch (IOException e) {
            System.err.println(e.getMessage());
        }
    }

    /**
     * 二维地图代理接口
     * @param request
     * @param response
     * @throws Exception
     */
    @GetMapping("/map/**")
    public void mapProxy(HttpServletRequest request, HttpServletResponse response){
        String key = request.getParameter("key");
        try {
            doMapGet(request,response,key);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 维地图代理
     * @param request
     * @param response
     * @param key
     * @throws IOException
     */
    private void doMapGet(HttpServletRequest request, HttpServletResponse response, String key) throws Exception {
        if(StringUtils.isEmpty(key)){
            response.setHeader("content-type", "text/html;charset=utf-8");
            response.getWriter().write("{code:403,msg:'缺少key值'}");
        }else{
            response.setContentType("image/png");
            // 获取前端openLayer请求参数集合
            Map<String, String[]> parameterMap = request.getParameterMap();
            // 获取服务ID编号
            Long serviceId = Long.valueOf(request.getRequestURL().toString().split("/")[5]);
            // 判断服务是否通过申请
            Integer res = proxyService.selectMyService(serviceId, key);
            if(res != null && res > 0){
                // 获取原地址
                ProxyService ps = proxyService.selectProxyServiceById(serviceId);
                // 被代理url
                String proxyUrl = ps.getServiceUrl();
                Set<String> keySet = parameterMap.keySet();
                String params = "";
                for (String k : keySet) {
                    if("key".equals(k)){
                        continue;
                    }
                    // 该参数是对象,不单独解析iserver不识别
                    if("origin".equals(k)){
                        params += (k + "=" + encoding(parameterMap.get(k)[0]) + "&");
                        continue;
                    }
                    // 代理时,=、&符号不必转码,否则iserver不识别
                    params += (k + "=" + parameterMap.get(k)[0] + "&");
                }
                int index = params.lastIndexOf("&");
                // 原地址
                String sourceUrl = proxyUrl + "/tileImage.png?" + params.substring(0,index);
                // 中文正则表达式
                String reg = "[^\u4e00-\u9fa5]";
                // 判断地址中是否存在中文
                if(!sourceUrl.matches(reg)){
                    String hzUrl = sourceUrl.replaceAll(reg,"");
                    proxyUrl = sourceUrl.replaceAll(hzUrl,encoding(hzUrl));
                }
                // 访问量自增1
                proxyService.webUsedCountIncreasing(serviceId);
                CloseableHttpClient httpclient = HttpClients.createDefault();
                CloseableHttpResponse closeableHttpResponse;
                //创建get请求
                HttpGet httpGet = new HttpGet(proxyUrl);
                Enumeration<String> headerNames = request.getHeaderNames();
                // 设置请求头
                while (headerNames.hasMoreElements()) {
                    String element = headerNames.nextElement();
                    httpGet.addHeader(element,request.getHeader(element));
                }
                // 提交参数发送请求
                closeableHttpResponse = httpclient.execute(httpGet);
                // 得到响应状态码
                int statusCode = closeableHttpResponse.getStatusLine().getStatusCode();
                // 判断响应信息是否正确
                if (statusCode != HttpStatus.SC_OK&&statusCode != HttpStatus.SC_NOT_MODIFIED) {
                    // 终止并抛出异常
                    httpGet.abort();
                    response.getWriter().write("HttpClient,error status code :" + statusCode);
                }
                HttpEntity entity = closeableHttpResponse.getEntity();
                if(StringUtils.isNotNull(entity)){
                    entity.writeTo(response.getOutputStream());
                }
            }else {
                // 审核未通过或者未申请该服务
                response.getOutputStream().write("{code:401,msg:'审核未通过或者未申请该服务'}".getBytes());
                return;
            }
        }
    }

    /**
     * 三维场景登录
     * @param request
     * @param response
     * @param key
     * @throws IOException
     */
    private void doScenePost(HttpServletRequest request, HttpServletResponse response,String key)throws IOException {
        response.setHeader("content-type", "text/html;charset=utf-8");
        if(StringUtils.isEmpty(key)){
            response.getOutputStream().write("{code:403,msg:'缺少key值'}".getBytes());
        }else {
            String requestUrl = request.getRequestURL().toString();
            String serviceId = requestUrl.split("/")[4];
            Integer res = ProxyServiceUtils.queryMyService(serviceId,key);
            // 审核已通过
            if(res != null&&res > 0){
                // 被代理url
                String proxyUrl = ProxyServiceUtils.queryServiceUrl(serviceId);
                if(StringUtils.isNotEmpty(proxyUrl)){
                    // 登录
                    if(requestUrl.indexOf("/login.json") > 0){
                        // 组装登录地址
                        if(proxyUrl.indexOf("/datas/") > 0){
                            proxyUrl = proxyUrl.split("/datas/")[0] + "/login.json";
                        }else {
                            response.getOutputStream().write("{code:404,msg:'地址格式不正确'}".getBytes());
                        }
                    }
                    // 访问量自增1
                    proxyService.webUsedCountIncreasing(Long.valueOf(serviceId));
                    CloseableHttpClient httpclient = HttpClients.createDefault();
                    CloseableHttpResponse closeableHttpResponse;
                    HttpPost httpPost = new HttpPost(proxyUrl);
                    // 读取post请求参数
                    BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
                    String line;
                    StringBuilder sb = new StringBuilder();
                    while ((line = reader.readLine()) != null) {
                        sb.append(line);
                    }
                    StringEntity stringEntity = new StringEntity(sb.toString());
                    httpPost.setEntity(stringEntity);
                    // 请求
                    closeableHttpResponse = httpclient.execute(httpPost);
                    // 得到响应信息
                    int statusCode = closeableHttpResponse.getStatusLine().getStatusCode();
                    if (statusCode != HttpStatus.SC_CREATED) {
                        // 终止并抛出异常
                        httpPost.abort();
                        response.getOutputStream().write(("HttpClient,error status code :" + statusCode).getBytes());
                    }
                    HttpEntity entity = closeableHttpResponse.getEntity();
                    entity.writeTo(response.getOutputStream());
                }else {
                    response.getOutputStream().write("{code:403,msg:'请检查地址是否正确'}".getBytes());
                }
            }else {
                // 审核未通过或者未申请该服务
                response.getOutputStream().write("{code:401,msg:'审核未通过或者未申请该服务'}".getBytes());
                return;
            }
        }
    }

    /**
     * 三维请求数据
     * @param request
     * @param response
     * @param key
     * @throws IOException
     */
    private void doSceneGet(HttpServletRequest request, HttpServletResponse response,String key) throws IOException{
        response.setHeader("content-type", "text/html;charset=utf-8");
        // 判断是否存在key
        if(StringUtils.isEmpty(key)){
            response.getOutputStream().write("{code:403,msg:'缺少key值'}".getBytes());
        }else{
            String requestUrl = request.getRequestURL().toString();
            String serviceId = request.getRequestURL().toString().split("/")[4];
            Integer res = ProxyServiceUtils.queryMyService(serviceId,key);;
            if(res != null&&res > 0){
                // 被代理url
                String proxyUrl = ProxyServiceUtils.queryServiceUrl(serviceId);
                // 登录
                if(requestUrl.indexOf("/login.json") > 0){
                    // 组装登录地址
                    if(proxyUrl.indexOf("/datas/") > 0){
                        proxyUrl = proxyUrl.split("/datas/")[0] + "/login.json";
                    }else {
                        response.getOutputStream().write("{code:404,msg:'地址格式不正确'}".getBytes());
                    }
                }
                // 请求图层配置文件
                if(requestUrl.endsWith("/config")){
                    proxyUrl = proxyUrl + "/config";
                }
                // .s3m文件
                if(requestUrl.indexOf(".s3m") > 0){
                    proxyUrl = proxyUrl + "/" + requestUrl.split("/realspace/")[1];
                }
                // 水面请求
                if(proxyUrl.indexOf(".water") > 0){
                    // 访问量自增1
                    proxyService.webUsedCountIncreasing(Long.valueOf(serviceId));
                }
                CloseableHttpClient httpclient = HttpClients.createDefault();
                CloseableHttpResponse closeableHttpResponse;
                //创建get请求
                HttpGet httpGet = new HttpGet(proxyUrl);
                // 设置请求和传输超时时间
                RequestConfig requestConfig = RequestConfig.custom()
                        .setSocketTimeout(4000).setConnectTimeout(4000).build();
                httpGet.setConfig(requestConfig);
                // 提交参数发送请求
                closeableHttpResponse = httpclient.execute(httpGet);
                // 得到响应状态码
                int statusCode = closeableHttpResponse.getStatusLine().getStatusCode();
                // 判断响应信息是否正确
                if (statusCode != HttpStatus.SC_OK&&statusCode != HttpStatus.SC_NOT_MODIFIED) {
                    // 终止并抛出异常
                    httpGet.abort();
                    response.getOutputStream().write(("HttpClient,error status code :" + statusCode).getBytes());
                }
                HttpEntity entity = closeableHttpResponse.getEntity();
                entity.writeTo(response.getOutputStream());
            }else {
                // 审核未通过或者未申请该服务
                response.getOutputStream().write("{code:401,msg:'审核未通过或者未申请该服务'}".getBytes());
                return;
            }
        }
    }

    /**
     * 转义字符串
     * @param str
     * @return
     * @throws Exception
     */
    private String encoding(String str) throws Exception{
        return URLEncoder.encode(str,"UTF-8");
    }

}


4.注意事项

代理时切忌不要自建类HttpServlet来实现,虽然代理效果可以实现,但项目如果使用了安全框架如spring-security,即使加入可以匿名访问,前端调用时会出现跨域问题,即使在doGet或doPost设置允许跨域访问也会被拦截,大概是因为自建Servlet不受spring管理。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值