spring-boot realizes the interface forwarding service, and supports various requests such as get and post at the same time

spring-boot implements interface forwarding service, and supports multiple requests such as get and post

(1) New class: ProxyController.java

package com.taobao.product.controller;

import com.taobao.framework.HttpResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.net.URISyntaxException;
import java.util.Enumeration;

import org.springframework.http.MediaType;
import java.io.IOException;
import java.net.URI;
import java.util.Collections;
import java.util.List;

import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClients;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;

/**
 * @Author: sunkaiyuan
 * @Date: 2023-05-23 9:02
 * @Desperation: TODO
 */
@Api(tags = "Proxy Service")
@RestController
@RequestMapping("/proxy")
@Slf4j
public class ProxyController {<!-- -->

    @ApiOperation(value = "Interface Forwarding")
    @RequestMapping("/dahua/**")
    public ResponseEntity<String> handleRequest(HttpServletRequest request) throws IOException, URISyntaxException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {<!-- -->
        String method = request. getMethod();
        String path = getPath(request);
        // remove /proxy/dahua from url
        path = path.substring(request.getContextPath().length() + "/proxy/dahua".length());
        URI targetUri = new URI("https://121.26.142.174:8443" + path);
        System.out.println(targetUri);
        HttpHeaders headers = getRequestHeaders(request);
        HttpEntity<?> entity = new HttpEntity<>(headers);

        RestTemplate restTemplate = new RestTemplate(getSecureHttpRequestFactory());
        if (method.equalsIgnoreCase(HttpMethod.GET.name())) {<!-- -->
            return restTemplate.exchange(targetUri, HttpMethod.GET, entity, String.class);
        } else if (method. equalsIgnoreCase(HttpMethod. POST. name())) {<!-- -->
            String requestBody = getRequestBody(request);
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<String> postEntity = new HttpEntity<>(requestBody, headers);
            return restTemplate.exchange(targetUri, HttpMethod.POST, postEntity, String.class);
        } else {<!-- -->
            return ResponseEntity.badRequest().body("Unsupported request method: " + method);
        }
    }

    private String getPath(HttpServletRequest request) {<!-- -->
        String contextPath = request. getContextPath();
        String servletPath = request. getServletPath();
        String pathInfo = request.getPathInfo() != null ? request.getPathInfo() : "";
        return contextPath + servletPath + pathInfo;
    }

    private HttpHeaders getRequestHeaders(HttpServletRequest request) {<!-- -->
        HttpHeaders headers = new HttpHeaders();
        Enumeration<String> headerNames = request. getHeaderNames();
        while (headerNames.hasMoreElements()) {<!-- -->
            String headerName = headerNames. nextElement();
            List<String> headerValues = Collections. list(request. getHeaders(headerName));
            headers. put(headerName, headerValues);
        }
        return headers;
    }

    private String getRequestBody(HttpServletRequest request) throws IOException {<!-- -->
        return request.getReader().lines().reduce("", (accumulator, actual) -> accumulator + actual);
    }

    private HttpComponentsClientHttpRequestFactory getSecureHttpRequestFactory() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {<!-- -->
        TrustManager[] trustAllCerts = new TrustManager[] {<!-- --> new X509TrustManager() {<!-- -->
            public X509Certificate[] getAcceptedIssuers() {<!-- -->
                return null;
            }

            public void checkClientTrusted(X509Certificate[] certs, String authType) {<!-- -->
            }

            public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {<!-- -->
            }
        } };

        SSLContext sslContext = SSLContext. getInstance("TLS");
        sslContext.init(null, trustAllCerts, null);

        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);

        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(HttpClients.custom().setSSLSocketFactory(csf).build());

        return requestFactory;
    }
}

(2) Code description:

This is a Java class named ProxyController. The code contains the following methods:

handleRequest(HttpServletRequest request)

This is a public method, the return type is ResponseEntity, some possible exceptions will be thrown. The purpose of this method is to process the HTTP request and return the corresponding response based on the incoming request object. This method is marked by the annotation @RequestMapping("/dahua/**"), which means that this method will be called only when the URL contains /proxy/dahua . This method implements the functionality of forwarding an incoming request to another URL and returning a response. If the request is not a GET or POST, an error response will be returned.

getPath(HttpServletRequest request)

This is a private method with a return type of String. This method receives a request object, gets the context path, servlet path, and path information from it, and combines them into a complete URL path and returns it.

getRequestHeaders(HttpServletRequest request)

This is a private method with a return type of HttpHeaders. This method takes a request object, gets all the request headers from it, puts them into a new HttpHeaders object, and returns that object.

getRequestBody(HttpServletRequest request)

This is a private method with a return type of String that may throw an IO exception. This method takes a request object, gets the request body (if any) from it, converts it to a string, and returns that string.

getSecureHttpRequestFactory()

This is a private method with a return type of HttpComponentsClientHttpRequestFactory, which may throw some exceptions. The purpose of this method is to create a secure HTTP request factory that allows us to connect to another URL via HTTPS. This method uses the TrustManager and SSLContext to implement trusting all certificates, sets it as the SSL socket factory in the request factory, and returns the request factory.

Besides that, the code also contains some annotations and variable declarations. Among them, the @ApiOperation annotation indicates that the method has operation description information; @RequestMapping("/dahua/**") indicates that when the URL contains /proxy/dahua, this method will be called. Variables method, path, targetUri, headers, entity, restTemplate , postEntity, requestFactory, etc. have corresponding uses in the code.