springboot +nginx 配置http2
说明
- nginx端使用http2+https,如果不使用https,浏览器会默认走http1.1
- 后台使用http2,不使用https,因为内部服务之间没必要每次校验证书
nginx配置
# user root;
worker_processes auto;
error_log D://nginx-log/error.log;
# error_log /dev/null;
#pid logs/nginx.pid;
events {
worker_connections 20000;
}
http {
access_log off;
include mime.types;
default_type application/octet-stream;
# 部分优化
sendfile on;
# 等数据包累积到一定大小才发送
tcp_nopush on;
#尽快发送数据包,和上面的二者相互矛盾。实际上,它们确实可以一起用,最终的效果是先填满包,再尽快发送。
tcp_nodelay on;
# 服务端为每个TCP连接最多可以保持多长时间,Nginx 的默认值是75秒,有些浏览器最多只保持60秒,所以我统一设置为 60
keepalive_timeout 60;
# 开启gzip
gzip on;
# 允许压缩的最小字节数
gzip_min_length 100;
# IE浏览器1-6版本禁用gzip
gzip_disable "msie6";
# 启用gzip的文件类型
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;
upstream gateway{
server 127.0.0.1:43797;
}
# http server
server {
listen 80;
listen [::]:80;
server_name yalong.com;
return 301 https://yalong.com$request_uri;
}
# HTTPS server
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name yalong.com;
ssl_certificate C:/myssl/selfsigned.crt;
ssl_certificate_key C:/myssl/selfsigned.key;
ssl_session_cache shared:SSL:100m;
ssl_session_timeout 1d;
ssl_buffer_size 1400;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;
location ^~ / {
# 后台服务使用h2c,这样不用校验两次证书,因为是http2协议,所以不能用proxy_pass反向代理,用grpc_pass反向代理
# 参数:grpc://和grpcs://分别是加密和不加密,这里使用h2c所以不加密
# proxy_pass http://gateway/;
grpc_pass grpc://gateway;
proxy_ssl_verify off;
proxy_set_header host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
add_header Kss-Upstream $upstream_addr;
}
}
}
java代码配置
<properties>
<java.version>8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- 只有4.x支持http2 -->
<okhttp.version>4.10.0</okhttp.version>
</properties>
<dependencies>
<!-- feign也使用okhttp,因为项目中更改了resttemplate的默认客户端为okhttp,并设置了h2c -->
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-openfeign</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>io.github.openfeign</groupId>-->
<!-- <artifactId>feign-okhttp</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 用undertow替换tomcat,这样java8即可支持http2/h2c -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
</dependencies>
server:
port: 43797
compression:
enabled: true
min-response-size: 1024
mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json
http2:
# 开启h2(HTTP/2 over TLS)
enabled: true
undertow:
# 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
io-threads: 4
# 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
worker-threads: 20
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
# 每块buffer的空间大小,越小的空间被利用越充分
buffer-size: 1024
# 是否分配的直接内存
direct-buffers: true
ssl:
# 关闭ssl,使用h2c(HTTP/2 over TCP),这样内部服务间调用就不需要使用https,使用http即可,并且是http2协议
# https://docs.spring.io/spring-boot/docs/2.5.8/reference/htmlsingle/#howto-configure-http2-h2c
enabled: false
# key-store: classpath:keystore.p12
# key-store-password: 123456
# key-store-type: PKCS12
# protocol: TLSv1.3
package com.example.demo.config;
import lombok.extern.slf4j.Slf4j;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.*;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
/**
* @author YaLong
* @date 2023/6/2
*/
@Configuration
@Slf4j
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
ClientHttpRequestFactory factory = httpRequestFactory();
return new RestTemplate(factory);
}
/**
* 工厂
*/
private ClientHttpRequestFactory httpRequestFactory() {
return new OkHttp3ClientHttpRequestFactory(okHttpConfigClient());
}
private SSLSocketFactory getSslSocketFactory() {
try {
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
sslContext.init(null, trustAllCerts(), new SecureRandom());
return sslContext.getSocketFactory();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private TrustManager[] trustAllCerts() {
return new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
};
}
private X509TrustManager getX509TrustManager() {
X509TrustManager trustManager = null;
try {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
}
trustManager = (X509TrustManager) trustManagers[0];
} catch (Exception e) {
e.printStackTrace();
}
return trustManager;
}
/**
* 客户端
*/
private OkHttpClient okHttpConfigClient() {
return new OkHttpClient().newBuilder()
.connectionPool(pool())
.connectTimeout(30, TimeUnit.SECONDS)
.retryOnConnectionFailure(Boolean.TRUE)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
// 若要使用h2c,必须用H2_PRIOR_KNOWLEDGE
// .protocols(Arrays.asList(Protocol.HTTP_1_1,Protocol.HTTP_2))
.protocols(Collections.singletonList(Protocol.H2_PRIOR_KNOWLEDGE))
.hostnameVerifier((hostname, session) -> true)
.sslSocketFactory(getSslSocketFactory(), getX509TrustManager())
.build();
}
/**
* 连接池
*/
public ConnectionPool pool() {
return new ConnectionPool(200, 5, TimeUnit.MINUTES);
}
}
你要是觉得写的还不错,就点个关注,可以评论区留下足迹,以后方便查看.
你要是觉得写的很辣鸡,评论区欢迎来对线!
欢迎转载!