功能描述
需要代理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管理。