1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        java代理http請求

        共 10326字,需瀏覽 21分鐘

         ·

        2022-05-07 11:40

        前言

        估計看到這個標(biāo)題你會覺得多此一舉,因為nginx完全可以實現(xiàn)代理,且配置非常方便。之前接到一個需求,服務(wù)器必須使用java程序進行代理,并記錄詳細(xì)的出入?yún)ⅲ员愫罄m(xù)根據(jù)日志查到問題。先暫且不糾結(jié)是否必要,來談?wù)劸唧w實現(xiàn)。

        需求明細(xì)

        1、使用http代理post接口請求(接口前綴一樣)
        2、能接收json或xml數(shù)據(jù),返pdf流文件或json數(shù)據(jù)
        3、詳細(xì)記錄出入?yún)?/p>

        具體實現(xiàn)

        俗話說無圖無真相,慣例邊上代碼邊解釋
        1、構(gòu)建springboot項目,添加pom.xml依賴

            <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.2.2.RELEASEversion>
        <relativePath/>
        parent>
        <groupId>cn.gudukegroupId>
        <artifactId>guduke-agentartifactId>
        <version>0.0.1-SNAPSHOTversion>
        <name>guduke-agent/name>
        <description>代理服務(wù)description>
        <properties>
        <java.version>1.8java.version>
        properties>
        <dependencies>
        <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
        <optional>trueoptional>
        dependency>
        <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-testartifactId>
        <scope>testscope>
        dependency>

        <dependency>
        <groupId>org.apache.httpcomponentsgroupId>
        <artifactId>httpclientartifactId>
        <version>4.5.10version>
        dependency>

        <dependency>
        <groupId>org.apache.httpcomponentsgroupId>
        <artifactId>httpmimeartifactId>
        <version>4.5.10version>
        dependency>
        <dependency>
        <groupId>com.alibabagroupId>
        <artifactId>fastjsonartifactId>
        <version>1.2.76version>
        dependency>

        <dependency>
        <groupId>ch.qos.logbackgroupId>
        <artifactId>logback-classicartifactId>
        <version>1.2.3version>
        <scope>compilescope>
        dependency>
        <dependency>
        <groupId>org.apache.logging.log4jgroupId>
        <artifactId>log4j-to-slf4jartifactId>
        <version>2.10.0version>
        <scope>compilescope>
        dependency>
        <dependency>
        <groupId>org.slf4jgroupId>
        <artifactId>jul-to-slf4jartifactId>
        <version>1.7.25version>
        <scope>compilescope>
        dependency>

        <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-aopartifactId>
        dependency>
        dependencies>

        2、application.yml添加配置信息

        server:
        servlet:
        context-path: /guduke-agent
        port: 9530
        # 需要代理的接口地址
        agent:
        insur: http://www.guduke.cn:20001/agent

        3、定義工具類AgentUtil

        /**
        * @ClassName AgentUtil
        * @Description 代理工具類
        * @Author yuxk
        * @Date 2021/10/8 20:15
        * @Version 1.0
        **/

        public class AgentUtil {

        public static final String CONTENT_LENGTH = "content-length";
        public static final String CONTENT_TYPE = "application/pdf";

        private static final Logger logger = LoggerFactory.getLogger(AgentUtil.class);
        private static PoolingHttpClientConnectionManager connMgr;
        private static RequestConfig requestConfig;
        # 設(shè)置1分鐘超時時間
        private static final int MAX_TIMEOUT = 60000;

        static {
        // 設(shè)置連接池
        connMgr = new PoolingHttpClientConnectionManager();
        // 設(shè)置連接池大小
        connMgr.setMaxTotal(100);
        connMgr.setDefaultMaxPerRoute(connMgr.getMaxTotal());
        connMgr.setValidateAfterInactivity(1000);
        RequestConfig.Builder configBuilder = RequestConfig.custom();
        // 設(shè)置連接超時
        configBuilder.setConnectTimeout(MAX_TIMEOUT);
        // 設(shè)置讀取超時
        configBuilder.setSocketTimeout(MAX_TIMEOUT);
        // 設(shè)置從連接池獲取連接實例的超時
        configBuilder.setConnectionRequestTimeout(MAX_TIMEOUT);
        requestConfig = configBuilder.build();
        }

        /**
        * @Author yuxk
        * @Description post請求
        * @Date 2022/4/15 9:05
        * @Param apiUrl 請求地址
        * @Param headersMap 請求頭
        * @Param json 請求參數(shù)
        * @Param infno 功能號
        * @Param contentType 請求類型
        * @Return java.util.Map
        **/

        public static Map doPost(String apiUrl, Map headersMap, Object json, String infno, String contentType) {
        Map resultMap = new HashMap<>();
        CloseableHttpClient httpClient = null;
        // 根據(jù)http或https構(gòu)建CloseableHttpClient對象
        if (apiUrl.startsWith("https")) {
        httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory())
        .setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).build();
        } else {
        httpClient = HttpClients.createDefault();
        }
        Object httpStr = null;
        HttpPost httpPost = new HttpPost(apiUrl);
        CloseableHttpResponse response = null;
        try {
        httpPost.setConfig(requestConfig);
        // 解決中文亂碼問題
        StringEntity stringEntity = new StringEntity(json.toString(), "UTF-8");
        stringEntity.setContentEncoding("UTF-8");
        stringEntity.setContentType(contentType);
        httpPost.setEntity(stringEntity);
        // 設(shè)置請求頭
        if (!headersMap.isEmpty()) {
        for (Map.Entry map : headersMap.entrySet()) {
        // 去除字段長度,提交會報錯
        if (!CONTENT_LENGTH.equals(map.getKey())) {
        httpPost.setHeader(map.getKey(), map.getValue());
        }
        }
        }
        response = httpClient.execute(httpPost);
        // 獲取返回的請求頭信息
        Map responseMap = new HashMap<>();
        Header[] allHeaders = response.getAllHeaders();
        for (Header header : allHeaders) {
        responseMap.put(header.getName(), header.getValue());
        }
        HttpEntity entity = response.getEntity();
        // 查看是否為流文件
        String disposition = responseMap.get("Content-Disposition");
        String type = responseMap.get("Content-Type");
        if (!StringUtils.isEmpty(disposition) || CONTENT_TYPE.equals(type)) {
        resultMap.put("Content-Disposition", disposition);
        if (!StringUtils.isEmpty(type)) {
        responseMap.put("Content-Type", type);
        }
        httpStr = EntityUtils.toByteArray(entity);
        } else {
        httpStr = EntityUtils.toString(entity, "UTF-8");
        }
        } catch (IOException e) {
        logger.error("調(diào)用服務(wù)異常:{}", e.getMessage());
        } finally {
        if (response != null) {
        try {
        EntityUtils.consume(response.getEntity());
        } catch (IOException e) {
        logger.error(e.getMessage());
        }
        }
        }
        resultMap.put("result", httpStr);
        return resultMap;
        }

        /**
        * @Author yuxk
        * @Description 創(chuàng)建SSL安全連接
        * @Date 2022/4/15 9:05
        * @Param
        * @Return org.apache.http.conn.ssl.SSLConnectionSocketFactory
        **/

        private static SSLConnectionSocketFactory createSSLConnSocketFactory() {
        SSLConnectionSocketFactory sslsf = null;
        try {
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
        @Override
        public boolean isTrusted(X509Certificate[] chain, String authType) {
        return true;
        }
        }).build();
        sslsf = new SSLConnectionSocketFactory(sslContext, new HostnameVerifier() {
        @Override
        public boolean verify(String arg0, SSLSession arg1) {
        return true;
        }
        });
        } catch (GeneralSecurityException e) {
        logger.error("SSL連接異常:{}", e.getMessage());
        }
        return sslsf;
        }

        /**
        * @Author yuxk
        * @Description 獲取隨機文件名
        * @Date 2022/4/15 9:05
        * @Param
        * @Return java.lang.String
        **/

        public static String getFilename() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        return sdf.format(new Date()) + (int) (Math.random() * (9000) + 1000);
        }

        /**
        * @Author yuxk
        * @Description request請求參數(shù)轉(zhuǎn)成字節(jié)數(shù)組
        * @Date 2022/4/15 9:04
        * @Param request
        * @Return byte[]
        **/

        public static byte[] getRequestPostBytes(HttpServletRequest request)
        throws IOException {
        int contentLength = request.getContentLength();
        if (contentLength < 0) {
        return null;
        }
        byte[] buffer = new byte[contentLength];
        for (int i = 0; i < contentLength; ) {
        int readlen = request.getInputStream().read(buffer, i,
        contentLength - i);
        if (readlen == -1) {
        break;
        }
        i += readlen;
        }
        return buffer;
        }


        }

        4、創(chuàng)建代理controller類AgentController

        /**
        * @ClassName AgentController
        * @Description 代理控制類
        * @Author yuxk
        * @Date 2021/10/8 20:08
        * @Version 1.0
        **/

        @RestController
        @Slf4j
        public class AgentController {

        @Value("${agent.insur}")
        private String insurUrl;

        @PostMapping("/insur/**")
        public ResponseEntity insur(HttpServletRequest request) throws IOException {
        String path = request.getServletPath();
        log.info("開始調(diào)用接口");
        // 獲取接口名稱
        String infno = path.replace("/insur", "");
        String actualno = infno.startsWith("/") ? infno.substring(1) : "";
        log.info("接口名稱:{}", actualno);
        // 獲取請求入?yún)?/span>
        byte[] bytes = AgentUtil.getRequestPostBytes(request);
        String param = new String(bytes, "UTF-8");
        log.info("請求入?yún)?{}", param);
        // 獲取請求頭數(shù)據(jù)
        Map headersMap = new HashMap<>(16);
        Enumeration headerNames = request.getHeaderNames();
        StringBuilder builder = new StringBuilder(16);
        while (headerNames.hasMoreElements()) {
        String name = headerNames.nextElement();
        String value = request.getHeader(name);
        headersMap.put(name, value);
        builder.append(name + "=" + value + ",");
        }
        log.info("請求頭參數(shù):{}", StringUtils.isEmpty(builder.toString()) ? "" : builder.substring(0, builder.length() - 1));
        // 獲取請求方式
        String contentType = request.getContentType();
        // 調(diào)用接口,獲取結(jié)果集和文件類型
        String realUrl= insurUrl + infno;
        Map resultMap = AgentUtil.doPost(realUrl, headersMap, param, contentType, actualno);
        String disposition = (String) resultMap.get("Content-Disposition");
        String type = (String) resultMap.get("Content-Type");
        if (!StringUtils.isEmpty(disposition) || AgentUtil.CONTENT_TYPE.equals(type)) {
        // 文件以流返回
        HttpHeaders headers = new HttpHeaders();
        if (!StringUtils.isEmpty(type)) {
        headers.add("Content-Type", type);
        }
        if (AgentUtil.CONTENT_TYPE.equals(type)) {
        headers.add("Content-Disposition", AgentUtil.getFilename() + ".pdf");
        } else {
        headers.add("Content-Disposition", disposition);
        }
        log.info("請求回參:{}", resultMap.get("result"));
        return new ResponseEntity<>(resultMap.get("result"), headers, HttpStatus.OK);
        }
        log.info("請求回參:{}", resultMap.get("result"));
        return new ResponseEntity<>(resultMap.get("result"), HttpStatus.OK);
        }

        }

        @PostMapping("/insur/**")?路徑帶**可以匹配多個路徑
        request.getServletPath()?獲取請求路徑如/insur/1101,目的是為了后面進行路徑替換
        request.getHeaderNames()?獲取所有的請求頭參數(shù),便于后面java請求時把原請求頭參數(shù)一并帶過去
        獲取請求結(jié)果之后的Content-Disposition和Content-Type數(shù)據(jù),若是流文件java以流返回,若是json數(shù)據(jù)直接返回
        5、構(gòu)建切面類ControllerAspect添加日志請求ID

        /**
        * @ClassName ControllerAspect
        * @Description TODO
        * @Author yuxk
        * @Date 2021/12/15 13:52
        * @Version 1.0
        **/

        @Component
        @Aspect
        public class ControllerAspect {


        @Pointcut("execution(* cn.hsa.powersi.controller.*.*(..))")
        public void executionService() {

        }

        @Before(value = "executionService()")
        public void doBefore(JoinPoint joinPoint) {
        // 添加日志打印
        String requestId = MDC.get("requestId");
        if (StringUtils.isEmpty(requestId)) {
        requestId = String.valueOf(UUID.randomUUID());
        MDC.put("traceID", requestId);
        }
        }

        @AfterReturning(pointcut = "executionService()")
        public void doAfter() {
        MDC.clear();
        }

        @AfterThrowing(pointcut = "executionService()", throwing = "e")
        public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
        MDC.clear();
        }

        }

        6、創(chuàng)建logback-spring.xml日志配置文件,保存出入?yún)⒌轿募?/p>

        復(fù)制"1.0" encoding="UTF-8"?>
        "false">

        "context" name="LOG_HOME" source="logging.file.path" defaultValue="/app/log/guduke-agent"/>


        "context" name="APP_NAME" source="spring.application.name" defaultValue="guduke-agent"/>

        "context" name="ROOT_LEVEL" source="logging.level.root" defaultValue="INFO"/>
        "context" name="PATTERN" source="logging.file.pattern"
        defaultValue="%d{yyyy-MM-dd HH:mm:ss.SSS} - [%X{traceID}] - [%thread] %-5level %logger{50}.%M\(%line\) - %msg%n"/>

        "context" name="MAXHISTORY" source="logging.file.maxHistory" defaultValue="180"/>

        "context" name="MAXFILESIZE" source="logging.file.maxFileSize" defaultValue="100MB"/>

        "context" name="TOTALSIZECAP" source="logging.file.totalSizeCap" defaultValue="10GB"/>


        "STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">

        ${PATTERN}



        "FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">

        ${LOG_HOME}/${APP_NAME}.%d{yyyy-MM-dd}.%i.log

        ${MAXHISTORY}
        ${MAXFILESIZE}
        ${TOTALSIZECAP}

        class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">

        ${PATTERN}





        "prod">

        "${ROOT_LEVEL}">

        "FILE"/>



        "!prod">
        "${ROOT_LEVEL}">
        "STDOUT"/>
        "FILE"/>



        瀏覽 57
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            成人A一级毛片免费看视频 | 免费观看性生交大片洗澡视频 | 亚洲无码三级片 | 纲手好紧蕾丝内裤动态图小说 | 日本在线一区 | 炮友自拍| 国产777777 | 偷偷操av | 91国产精品在线 | 卖婬全过程无遮挡免费视频 |