通过java实现服务代理

比如我们现在有一个服务地址,但是我们有不想把这个地址让别人知道,所有我们可以生成一个假的地址给他们,然后这个地址通过nginx进入到我们处理代理服务的接口里面,先找到真实的地址,然后再转发

比如下面的信息,我们把代理地址给用户(后面可以给接收token的参数gctk(参数名)),可以根据这个token信息判断,是否有访问服务的权限

真实地址
http://www.rog.org/server/rest/services/aa/MapServer
代理后的地址
http://127.0.0.1/skmap/forward/services/3da4413391a4403b877e38241e752cff/server/rest/services/aa/MapServer?f=json&gctk=tokenValue

nginx配置

location /skmap/ {
	    if ($request_method = 'OPTIONS') {return 204;}
	    add_header Access-Control-Allow-Credentials true;
	    add_header Access-Control-Allow-Origin *;
	    add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
	    add_header Access-Control-Allow-Headers *;
            proxy_pass   http://127.0.0.1:55096/;
            proxy_set_header Host $host;
	    proxy_set_header X-Real-IP $remote_addr;
	    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

controller

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 资源访问权限验证接口
 *
 */
@RestController
public class VisitAuthController {

    @Autowired
    private VisitAuthService visitAuthService;

    @ResponseBody
    @RequestMapping(value = "/forward/services/**", method = {RequestMethod.POST, RequestMethod.GET})
    public void service(HttpServletRequest request, HttpServletResponse response) {
        visitAuthService.proxyServices(request, response);
    }
}

service


import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

/**
 * @author alex
 * @since 2020/02/28
 */
@Service
public class VisitAuthService {

    private static Logger LOG = LoggerFactory.getLogger(VisitAuthService.class);

    private static final String TOKEN_KEY = "gctk";


    public void proxyServices(HttpServletRequest request, HttpServletResponse response) {
        VisitRequestModel visitRequestModel = new VisitRequestModel(request, "/forward/services");
        String code = visitRequestModel.getCode();
        String key = visitRequestModel.getKey();
        String queryString = visitRequestModel.getQueryString();
        Resource resourceDO = resourceRepository.getByCode(code);//根据code查询资源,获取真实url地址
        if (resourceDO == null) {
            String error = "No Resource";
            returnResponse(response, error);
            return;
        }
        
        /**
         * 至此 这里没有贴判断权限的代码权限 访问原始地址获取数据 输出数据
         */

        String queryStringDecode = queryString;
        // 首先将代理请求中的token信息剔除
        if (StringUtils.isNotBlank(queryStringDecode)) {
            queryStringDecode = queryStringDecode.replaceFirst(TOKEN_KEY + "=" + visitRequestModel.getToken(), "");
        }
        // 获取真实地址
        String originUrl = resourceDO.getOriginUrl();
        if (StringUtils.isNotBlank(queryStringDecode)) {
            originUrl += "?" + queryStringDecode;
        }


        ProxyHttpRequestUtil.ResponseInfo responseInfo = ProxyHttpRequestUtil.proxyRequest(request, originUrl, response);
        visitRequestModel.setEndTime(System.currentTimeMillis());
        if (responseInfo != null) {
           //添加预览记录
        }
    }

    
    /**
     * 返回信息
     *
     * @param response 响应对象
     * @param data     信息
     */
    private void returnResponse(HttpServletResponse response, String data) {
        try {
            byte[] responseData = data.getBytes();
            OutputStream outputStream = response.getOutputStream();
            outputStream.write(responseData);
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
VisitRequestModel

import cn.com.geoscene.micro.qx.utils.StringCommonUtils;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * 资源请求对象model类
 *
 */
@Data
public class VisitRequestModel {
    private String method;                  //请求方法
    private String scheme;                  //请求协议
    private String host;                    //请求host
    private String origin;
    private String referer;                 //请求接口的页面url,即refer
    private String token;                   //token信息
    private String queryString;             //query信息,及url中?后的信息
    private String requestURI;              //请求地址,例如:'/server/rest/*******/MapServer/0/query'
    private String code;               //代理标识,requestURI的第一层目录:'*******'
    private Map<String, String> cookieMap;  //请求cookie信息 暂未使用
    private String key;                     //应用code
    private long beginTime;                 //请求开始时间
    private long endTime;                   //请求结束时间

    private String type;                    //资源类型

    public VisitRequestModel(HttpServletRequest request, String url) {
        beginTime = System.currentTimeMillis();
        method = request.getMethod();
        host = request.getHeader("host");
        scheme = request.getHeader("X-Scheme");
        referer = request.getHeader("referer");
        origin = request.getHeader("origin");
        requestURI = StringCommonUtils.ChangeUTFToISO(request.getRequestURI());
        String rUri = requestURI.replaceFirst(url, "");
        String[] split = rUri.split("/");
        code = split[1];
        queryString = request.getQueryString();
        if(StringUtils.isNotBlank(queryString)){
            if(queryString.contains("key")){
                String[] params = queryString.split("&");
                String newParam = "";
                for (String param : params) {
                    if(param.contains("key")){
                        key = param.replace("key=", "");
                    }else {
                        newParam = newParam + param + "&";
                    }
                    if(newParam.endsWith("&")){
                        newParam = newParam.substring(0, newParam.length() - 1);
                    }
                    queryString = newParam;

                }
            }
        }
    }

    public long getRunningTime() {
        return endTime - beginTime;
    }
}


import org.apache.commons.lang3.StringUtils;

import java.nio.charset.StandardCharsets;

/**
 * 字符工具类
 **/
public class StringCommonUtils {

   

    /**
     * 将服务地址中url中文改成ASCII字符集
     *
     * @param serverUrlUTF utf-8字符串
     * @return ascii字符串
     */
    public static String ChangeUTFToISO(String serverUrlUTF) {
        StringBuilder resultStr = new StringBuilder();
        if (StringUtils.isBlank(serverUrlUTF)) return serverUrlUTF;
        for (int i = 0; i < serverUrlUTF.length(); i++) {
            char c = serverUrlUTF.charAt(i);
            if (c <= 255) {
                resultStr.append(c);
            } else {
                byte[] b;
                try {
                    b = String.valueOf(c).getBytes(StandardCharsets.UTF_8);
                } catch (Exception ex) {
                    System.out.println(ex);
                    b = new byte[0];
                }
                for (int value : b) {
                    int k = value;
                    if (k < 0)
                        k += 256;
                    resultStr.append("%").append(Integer.toHexString(k).toUpperCase());
                }
            }
        }
        return resultStr.toString();
    }
    
}


import org.apache.commons.lang3.StringUtils;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.*;

/**
 */
public class ProxyHttpRequestUtil {

    /**
     * 代理请求
     *
     * @param request  请求信息
     * @param proxyUrl 代理地址
     * @param response 接收的答复
     */
    public static ResponseInfo proxyRequest(HttpServletRequest request, String proxyUrl, HttpServletResponse response) {
        ResponseInfo responseInfo = null;
        try {
            RequestInfo requestInfo = ReadRequestInfo(request);
            HttpURLConnection httpURLConnection = CreateProxyRequestConnection(proxyUrl, requestInfo);
            httpURLConnection.setConnectTimeout(60000);//设置超时时间1分钟
            responseInfo = ReadResponseInfo(httpURLConnection);
            WriteResponseInfo(responseInfo, response);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return responseInfo;
    }

    /**
     * 从HttpServletRequest中读取请求信息
     *
     * @param request HttpServletRequest
     * @return RequestInfo 请求体对象
     */
    public static RequestInfo ReadRequestInfo(HttpServletRequest request) throws IOException {
        RequestInfo requestInfo = new RequestInfo();
        String method = request.getMethod();
        requestInfo.setMethod(method);
        String requestUrl = request.getRequestURL().toString();
        requestInfo.setRequestUrl(requestUrl);
        String queryString = request.getQueryString();
        requestInfo.setQueryString(queryString);
        String characterEncoding = request.getCharacterEncoding();
        requestInfo.setCharacterEncoding(characterEncoding);
        Map<String, String> headMap = new HashMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headName = headerNames.nextElement();
            String headerValue = request.getHeader(headName);
            headMap.put(headName, headerValue);
        }
        requestInfo.setHeader(headMap);
        int contentLength = request.getContentLength();
        if (contentLength > 0) {
            requestInfo.setContentLength(contentLength);
            byte[] requestData = new byte[contentLength];
            DataInputStream dataInputStream = new DataInputStream(request.getInputStream());
            dataInputStream.readFully(requestData);
            dataInputStream.close();
            requestInfo.setRequestData(requestData);
        }
        return requestInfo;
    }

    /**
     * 读取响应信息
     *
     * @param connection HttpURLConnection 请求连接
     * @return ResponseInfo 响应体对象
     */
    public static ResponseInfo ReadResponseInfo(HttpURLConnection connection) {
        long begin = System.currentTimeMillis();
        ResponseInfo responseInfo = new ResponseInfo();
        if (connection != null) {
            try {
                int responseCode = connection.getResponseCode();//响应行
                long end = System.currentTimeMillis() - begin;//本次请求用时
                responseInfo.setWaitTime(end);
                responseInfo.setResponseCode(responseCode);

                Map<String, List<String>> headerFields = connection.getHeaderFields();//响应头
                responseInfo.setHeader(headerFields);

                InputStream byteStream;//响应体
                if (responseCode >= 400 && connection.getErrorStream() != null) {
                    byteStream = connection.getErrorStream();
                } else {
                    byteStream = connection.getInputStream();
                }
                ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                final int length = 4096;
                byte[] bytes = new byte[length];
                int bytesRead;
                while ((bytesRead = byteStream.read(bytes, 0, length)) > 0) {
                    buffer.write(bytes, 0, bytesRead);
                }
                buffer.flush();
                byte[] responseData = buffer.toByteArray();
                responseInfo.setResponseData(responseData);
                byteStream.close();
            } catch (SocketTimeoutException e) {
                responseInfo.setResponseCode(408);
                responseInfo.setWaitTime(-1);
                System.out.println("请求超时");
            }
            catch (IOException e) {
                responseInfo.setResponseCode(500);
                responseInfo.setWaitTime(-1);
                System.out.println("请求错误");
            }
        }
        return responseInfo;
    }

    /**
     * 创建代理请求链接
     *
     * @param url         请求地址,必须是完整的url,http[s]://domain[:port]/****
     * @param requestInfo 请求信息对象
     */
    public static HttpURLConnection CreateProxyRequestConnection(String url, RequestInfo requestInfo) throws IOException {
        HttpURLConnection httpURLConnection = null;
        if (StringUtils.isNotBlank(url)) {
            if (url.toUpperCase().startsWith("HTTPS")) {
                httpURLConnection = DoRequest(url, requestInfo.getMethod(), requestInfo.getHeader(),
                        requestInfo.getRequestData(), true);
            } else {
                httpURLConnection = DoRequest(url, requestInfo.getMethod(), requestInfo.getHeader(),
                        requestInfo.getRequestData(), false);
            }
        }
        return httpURLConnection;
    }

    /**
     * 将响应信息写入HttpServletResponse中
     *
     * @param responseInfo 响应信息
     * @param response     HttpServletResponse
     */
    public static void WriteResponseInfo(ResponseInfo responseInfo, HttpServletResponse response) throws IOException {
        if (null != responseInfo && null != responseInfo.getResponseCode()) {
            Map<String, List<String>> headerFields = responseInfo.getHeader();
            passHeadersInfo(response, headerFields);
            int code = responseInfo.getResponseCode();
            response.setStatus(code);
            if (code > 0 && code < 400) {
                byte[] responseData = responseInfo.getResponseData();
                OutputStream outputStream = response.getOutputStream();
                outputStream.write(responseData);
                outputStream.close();
            }
        }
    }

    /**
     * 创建HTTP请求链接
     *
     * @param urlStr   请求完整url地址 http[s]://Host/Path?QueryString
     * @param method   请求方式
     * @param head     请求头信息
     * @param body     请求体信息
     * @param security 安全协议,https->true
     * @return
     * @throws IOException
     */
    private static HttpURLConnection DoRequest(String urlStr, String method, Map<String, String> head, byte[] body, boolean security) throws IOException {

        URL url = new URL(urlStr);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        // https
        if (security) {

        }
        connection.setConnectTimeout(5000);
        connection.setReadTimeout(10000);
        connection.setRequestMethod(method);
        passHeadersInfo(connection, head);
        if (body != null && body.length > 0 || method.equals("POST")) {
            if (body == null) {
                body = new byte[0];
            }
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);
            OutputStream os = connection.getOutputStream();
            os.write(body);
            os.close();
        }
        return connection;
    }

    /**
     * 将Header信息 放到请求头中
     *
     * @param connection
     * @param header
     */
    private static void passHeadersInfo(HttpURLConnection connection, Map<String, String> header) {
        if (null != header && header.size() > 0) {
            for (String headerName : header.keySet()) {
                String headerValue = header.get(headerName);
                connection.setRequestProperty(headerName, headerValue);
            }
        }
    }

    /**
     * 将Header信息 放到响应头中
     *
     * @param response
     * @param headerFields
     */
    private static void passHeadersInfo(HttpServletResponse response, Map<String, List<String>> headerFields) {
        if (null == headerFields) {
            return;
        }
        Set<String> headerFieldsSet = headerFields.keySet();
        for (String headerFieldKey : headerFieldsSet) {
            if (headerFieldKey != null && headerFieldKey.toLowerCase().equals("accept-ranges")) {
                continue;
            }
            List<String> headerFieldValue = headerFields.get(headerFieldKey);
            StringBuilder sb = new StringBuilder();
            for (String value : headerFieldValue) {
                if (headerFieldKey != null && headerFieldKey.toLowerCase().equals("content-type")) {
                    if (value != null && value.toLowerCase().contains("application/vnd.ogc.wms_xml")) {
                        value = "text/xml";
                    }
                }
                if (headerFieldKey != null && headerFieldKey.toLowerCase().equals("transfer-encoding")) {
                    if (value != null && value.toLowerCase().equals("chunked")) {
                        continue;
                    }
                }
                sb.append(value);
                sb.append("");
            }
            if (headerFieldKey != null) {
                response.addHeader(headerFieldKey, removeCRLF(sb.toString()));
            }
        }
    }

    /**
     * 将ServletInputStream转ByteArrayInputStream 因为 ServletInputStream
     * 被Tomcat做了优化,ServletInputStream.available()是得不到数据长度的,这样得到的就是一个字节数。
     * 所以把ServletInputStream转换为ByteArrayInputStream拿到数据长度,否则后续使用该ServletInputStream可能为空
     *
     * @param sis
     * @return
     */
    public static byte[] convertServletInputStream(ServletInputStream sis) {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        int n = 0;
        try {
            while ((n = sis.read(buffer)) != -1) {
                output.write(buffer, 0, n);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return output.toByteArray();
    }

    public static String removeCRLF(String inputLine) {
        String filteredLine = inputLine;
        if (hasCRLF(inputLine)) {
            filteredLine = filteredLine.replace("\n", "").replace("\r", "");
        }
        return filteredLine;
    }

    public static String replaceCRLF(String inputLine, String replaceString) {
        String filteredLine = inputLine;
        if (hasCRLF(inputLine)) {
            filteredLine = filteredLine.replace("\n", replaceString).replace("\r", replaceString);
        }
        return filteredLine;
    }

    public static boolean hasCRLF(String inputLine) {
        return inputLine.contains("\n") || inputLine.contains("\r");
    }

    public static class RequestInfo {
        private String method;                   //请求方法
        private String requestUrl;               //请求url
        private String queryString;              //参数
        private String characterEncoding;        //编码方式
        private Integer contentLength;           //请求内容长度
        private byte[] requestData;              //请求内容数据
        private Map<String, String> header;      //请求头信息

        public String getMethod() {
            return method;
        }

        public void setMethod(String method) {
            this.method = method;
        }

        public String getRequestUrl() {
            return requestUrl;
        }

        public void setRequestUrl(String requestUrl) {
            this.requestUrl = requestUrl;
        }

        public String getQueryString() {
            return queryString;
        }

        public void setQueryString(String queryString) {
            this.queryString = queryString;
        }

        public String getCharacterEncoding() {
            return characterEncoding;
        }

        public void setCharacterEncoding(String characterEncoding) {
            this.characterEncoding = characterEncoding;
        }

        public Integer getContentLength() {
            return contentLength;
        }

        public void setContentLength(Integer contentLength) {
            this.contentLength = contentLength;
        }

        public byte[] getRequestData() {
            return requestData;
        }

        public void setRequestData(byte[] requestData) {
            this.requestData = requestData;
        }

        public Map<String, String> getHeader() {
            return header;
        }

        public void setHeader(Map<String, String> header) {
            this.header = header;
        }
    }

    public static class ResponseInfo {
        private Integer responseCode;
        private Map<String, List<String>> header;
        private byte[] responseData;
        private String responseString;
        private long waitTime;

        public Integer getResponseCode() {
            return responseCode;
        }

        public void setResponseCode(Integer responseCode) {
            this.responseCode = responseCode;
        }

        public Map<String, List<String>> getHeader() {
            return header;
        }

        public void setHeader(Map<String, List<String>> header) {
            this.header = header;
        }

        public byte[] getResponseData() {
            return responseData;
        }

        public void setResponseData(byte[] responseData) {
            this.responseData = responseData;
        }

        public String getResponseString() {
            return responseString;
        }

        public void setResponseString(String responseString) {
            this.responseString = responseString;
        }

        public long getWaitTime() {
            return waitTime;
        }

        public void setWaitTime(long waitTime) {
            this.waitTime = waitTime;
        }
    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基本原理: 代理服务器打开一个端口接收浏览器发来的访问某个站点的请求,从请求的字符串中解析出用户想访问哪个网页,让后通过URL对象建立输入流读取相应的网页内容,最后按照web服务器的工作方式将网页内容发送给用户浏览器 源程序: import java.net.*; import java.io.*; public class MyProxyServer { public static void main(String args[]) { try { ServerSocket ss=new ServerSocket(8080); System.out.println("proxy server OK"); while (true) { Socket s=ss.accept(); process p=new process(s); Thread t=new Thread(p); t.start(); } } catch (Exception e) { System.out.println(e); } } }; class process implements Runnable { Socket s; public process(Socket s1) { s=s1; } public void run() { String content=" "; try { PrintStream out=new PrintStream(s.getOutputStream()); BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream())); String info=in.readLine(); System.out.println("now got "+info); int sp1=info.indexOf(' '); int sp2=info.indexOf(' ',sp1+1); String gotourl=info.substring(sp1,sp2); System.out.println("now connecting "+gotourl); URL con=new URL(gotourl); InputStream gotoin=con.openStream(); int n=gotoin.available(); byte buf[]=new byte[1024]; out.println("HTTP/1.0 200 OK"); out.println("MIME_version:1.0"); out.println("Content_Type:text/html"); out.println("Content_Length:"+n); out.println(" "); while ((n=gotoin.read(buf))>=0) { out.write(buf,0,n); } out.close(); s.close(); } catch (IOException e) { System.out.println("Exception:"+e); } } };

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值