nginx 正向代理 http https 标准端口80和443 非80和443端口 java 示例


更新记录
2024-01-11
在“章节一”增加nginx需要编译proxy_connect模块的提示和参考博客。
2024-01-11
在“章节四”增加502 Bad Gateway的情况处理。

前言

        前段时间,在搞nginx正向代理,实现一个端口代理http和https的能力,因为之前都是用反向代理的模式配置第三方地址,这样导致nginx会启动很多端口,然后还要开通这么多端口的防火墙策略,所以为了一切从简,决定捣鼓一番。
        查了很多博客,也感谢各位开发者的共享,不过在查找资料中,也觉得现有的教程或示例多少存在不足之处,或是只能代理标准端口80和443,或是能代理所有端口,但是没有演示代码怎么写,所以博主在整合百家之长后写下一点心得和示例,方便有需要的人白嫖。
        最好能给博主点个免费的赞支持一下,如果有更好的想法或其他疑问,也可以在评论里说明,博主会和你一起探讨。


一、nginx版本和安装

        nginx的安装本文不做说明,C站有很多详细的安装教程博客。
        nginx版本和安装的模块,在使用正向代理功能时,nginx需要编译ngx_http_proxy_connect_module模块:

./nginx -V

nginx version: nginx/1.14.2
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) 
built with OpenSSL 1.1.1q  5 Jul 2022
TLS SNI support enabled
configure arguments: --prefix=/home/test/app/nginx --with-openssl=/home/test/nginx/openssl-1.1.1q --with-pcre=/home/test/nginx/pcre-8.45 --with-zlib=/home/test/nginx/zlib-1.2.12 --with-http_stub_status_module --with-http_ssl_module --with-stream

ngx_http_proxy_connect_module参考博客:
1、CentOs7 给nginx安装ngx_http_proxy_connect_module模块,配置正向代理支持https
2、NGINX编译ngx_http_proxy_connect_module及做正向代理

二、nginx配置说明

        重要参数均以注释形式给出,各位也可以与其他博客对比下配置差异,也可以深究各个配置的差异影响。

# http模块
http {
    # mime类型,根据自己实际需求配置,不是本文重点
    include       mime.types;
    # 默认类型
    default_type  application/octet-stream;
    # log格式,根据自己实际需求配置,不是本文重点
    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;
    # 开启sendfile,根据自己实际需求配置,不是本文重点
    sendfile        on;

    # 超时时间,根据自己实际需求配置,不是本文重点
    keepalive_timeout  65;
    # 开启gzip压缩,根据自己实际需求配置,不是本文重点
    #gzip  on;

    server {
        # 监听端口
        listen       10086;
        # DNS解析 有效时间300秒 支持IPv6协议
        resolver 114.114.114.114 valid=300s ipv6=on;
        # 开启代理
        proxy_connect;
        # 代理白名单端口,允许所有端口
        proxy_connect_allow all;

        # 核心配置
        location / {
    		# scheme http和https 
    		# http_host 目标地址和端口
    		# request_uri 接口请求地址
            proxy_pass $scheme://$http_host$request_uri;
            # 使用http 1.1
            proxy_http_version 1.1;
            # 开启携带域名,防止目标存在SNI情况
            proxy_ssl_server_name on;
            # 请求头携带目标地址
            proxy_set_header Host $http_host;
        }
    }
}

三、java代码示例

        前言中博主也有提到,少有将配置和代码结合的博文,也可能其他开发者使用的非java开发语言,本文只演示java如何使用上述配置发送post请求。

1、引入依赖

        <!-- httpclient 会自动引入 httpcore commons-codec commons-logging -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <!-- 高版本测试通过,低版本未测试,请自行测试 -->
            <version>4.5.3</version>
        </dependency>

2、代码演示

package org.example;

import org.apache.http.HttpHost;
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.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

/**
 * @author 系统异常
 * @version 1.0
 * @date 2024/1/2 10:17
 * @description 代理测试类
 */
public class HttpProxyTest {
    public static void main(String[] args) {
        // https标准443端口,根据自身情况修改
        String url = "https://www.baidu.com";
        // http标准80端口,根据自身情况修改
        url = "http://www.baidu.com";
        // https非标准443端口,根据自身情况修改
        url = "https://www.baidu.com:8080";
        // http非标准80端口,根据自身情况修改
        url = "http://www.baidu.com:8080";

        // 测试报文
        String request = "{\"test\":\"123456\"}";
        try {
            // 信任所有证书,如果各位调用的地址都是标准的,则不需要此构造方法,直接使用 HttpClients.createDefault() 即可
            SSLConnectionSocketFactory scsf = new SSLConnectionSocketFactory(SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build(), NoopHostnameVerifier.INSTANCE);
            CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(scsf).build();

            // 请求配置
            int connTimeOut = 10000;
            int readTimeOut = 10000;
            String proxyIp = "192.168.109.137";
            int proxyPort = 10086;
            RequestConfig.Builder customReqConf = getBuilder(connTimeOut, readTimeOut, proxyIp, proxyPort);

            // 构建HttpPost请求
            HttpPost httpPost = new HttpPost(url);
            StringEntity stringEntity = new StringEntity(request);
            httpPost.setEntity(stringEntity);
            httpPost.setConfig(customReqConf.build());

            // 执行请求
            CloseableHttpResponse response = httpClient.execute(httpPost);
            if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) {
                System.out.println("请求成功");
            } else {
                System.out.println("请求失败");
            }

            // 获取响应报文
            String result = EntityUtils.toString(response.getEntity());
            System.out.println("响应 " + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取自定义的RequestConfig.Builder对象
     *
     * @param connTimeOut 连接超时时间,单位为毫秒
     * @param readTimeOut 读取超时时间,单位为毫秒
     * @param proxyIp     代理服务器的IP地址
     * @param proxyPort   代理服务器的端口号
     * @return 自定义的RequestConfig.Builder对象
     */
    private static RequestConfig.Builder getBuilder(int connTimeOut, int readTimeOut, String proxyIp, int proxyPort) {
        RequestConfig.Builder customReqConf = RequestConfig.custom();
        // 连接超时
        customReqConf.setConnectTimeout(connTimeOut);
        // 读取超时
        customReqConf.setSocketTimeout(readTimeOut);

        // 代理
        if (proxyIp != null && proxyPort > 0) {
            HttpHost proxy = new HttpHost(proxyIp, proxyPort, "http");
            customReqConf.setProxy(proxy);
        }
        return customReqConf;
    }
}

        各位还可以测试下低版本的依赖,以及其他端口或形式的url,如果不兼容的情况,欢迎在评论区指出。


四、报错说明

        在捣鼓过程中,出现过几种报错也列举在此,方便各位开发者对照。
1、

javx.netssL.SLHndshakexception: sn.security,validator.validatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to mequested tanget

2、

javax.net.ssl.SSLPeerUnverifiedException: Certificate for <xxx.xxx.xx.xx> doesn't match any of the subject alternative names: [*.xxx.com, xxx.com]

3、

curl -vvv -d '' -x 192.168.109.137:10086 https://xxx.xxx.com/query
* About to connect() to proxy 192.168.109.137 port 10086 (#0)
*   Trying 192.168.109.137...
* Connected to 192.168.109.137 (192.168.109.137) port 10086 (#0)
* Establish HTTP proxy tunnel to xxx.xxx.com:443
> CONNECT xxx.xxx.com:443 HTTP/1.1
> Host: xxx.xxx.com:443
> User-Agent: curl/7.29.0
> Proxy-Connection: Keep-Alive
> 
< HTTP/1.1 502 Bad Gateway
< Server: nginx/1.14.2
< Date: Thu, 11 Jan 2024 08:04:16 GMT
< Content-Type: text/html
< Content-Length: 173
< Connection: close
< 
* Received HTTP code 502 from proxy after CONNECT
* Connection #0 to host 192.168.109.137 left intact
curl: (56) Received HTTP code 502 from proxy after CONNECT

1和2这两种都是由于SSL忽略证书的写法有问题(错误的代码没有保留,尴尬);第三种是可能是由于ipv6解析打开的问题,只需要把上面的DNS解析调整一下(resolver 114.114.114.114 valid=300s ipv6=off;)就可以了。文中信任所有证书的方法和ipv6的问题处理亲测好使的很,如果有问题,欢迎在评论区讨论!

  • 9
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
要在Java中使用Nginx进行正向代理,需要进行以下步骤: 1. 在Nginx的配置文件中添加代理服务器的配置。可以使用命令`vim nginx.conf`编辑配置文件,在`server`块内添加如下配置: ``` server { listen 6443; location / { proxy_pass $scheme://$http_host$request_uri; } } ``` 2. 保存并退出配置文件,然后使用`./nginx`命令启动Nginx。 3. 确认Nginx已经成功运行,可以使用命令`ps -ef|grep nginx`来查看Nginx的进程。 4. 在Java代码中使用Nginx进行正向代理。你可以使用`java.net`包中的`Proxy`类来设置代理服务器的地址和端口,然后在HttpURLConnection或HttpClient中使用该代理进行请求。 例如,使用JavaHttpURLConnection来发送GET请求的示例代码如下: ```java URL url = new URL("https://api.weixin.qq.com"); Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 6443)); HttpURLConnection connection = (HttpURLConnection) url.openConnection(proxy); connection.setRequestMethod("GET"); // 添加请求头等其他必要的操作 int responseCode = connection.getResponseCode(); // 处理响应等其他操作 ``` 在以上示例中,我们将代理服务器的地址设置为`127.0.0.1`,端口设置为`6443`,然后通过代理服务器发送GET请求到`https://api.weixin.qq.com`。 请注意,以上代码仅为示例,实际使用时可能需要根据具体需求进行修改。此外,还可以使用其他HTTP客户端库,如Apache HttpClient等,来发送带有代理的请求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [nginx正向代理java代理请求](https://blog.csdn.net/attacker_p/article/details/125636072)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九二战歌

原创不易,尽量不白瓢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值