国产chinesehdxxxx野外,国产av无码专区亚洲av琪琪,播放男人添女人下边视频,成人国产精品一区二区免费看,chinese丰满人妻videos

Micronaut 配置 HTTP 服務(wù)器

2023-03-07 17:47 更新

HTTP 服務(wù)器具有許多配置選項(xiàng)。它們?cè)跀U(kuò)展 HttpServerConfiguration 的 NettyHttpServerConfiguration 配置類中定義。

以下示例顯示了如何通過(guò)配置文件(例如 application.yml)調(diào)整服務(wù)器的配置選項(xiàng):

配置 HTTP 服務(wù)器設(shè)置

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.server.maxRequestSize=1MB
micronaut.server.host=localhost
micronaut.server.netty.maxHeaderSize=500KB
micronaut.server.netty.worker.threads=8
micronaut.server.netty.childOptions.autoRead=true
micronaut:
  server:
    maxRequestSize: 1MB
    host: localhost
    netty:
      maxHeaderSize: 500KB
      worker:
        threads: 8
      childOptions:
        autoRead: true
[micronaut]
  [micronaut.server]
    maxRequestSize="1MB"
    host="localhost"
    [micronaut.server.netty]
      maxHeaderSize="500KB"
      [micronaut.server.netty.worker]
        threads=8
      [micronaut.server.netty.childOptions]
        autoRead=true
micronaut {
  server {
    maxRequestSize = "1MB"
    host = "localhost"
    netty {
      maxHeaderSize = "500KB"
      worker {
        threads = 8
      }
      childOptions {
        autoRead = true
      }
    }
  }
}
{
  micronaut {
    server {
      maxRequestSize = "1MB"
      host = "localhost"
      netty {
        maxHeaderSize = "500KB"
        worker {
          threads = 8
        }
        childOptions {
          autoRead = true
        }
      }
    }
  }
}
{
  "micronaut": {
    "server": {
      "maxRequestSize": "1MB",
      "host": "localhost",
      "netty": {
        "maxHeaderSize": "500KB",
        "worker": {
          "threads": 8
        },
        "childOptions": {
          "autoRead": true
        }
      }
    }
  }
}
  • 默認(rèn)情況下,Micronaut 綁定到所有網(wǎng)絡(luò)接口。使用 localhost 僅綁定到環(huán)回網(wǎng)絡(luò)接口

  • maxHeaderSize 設(shè)置標(biāo)題的最大大小

  • worker.threads 指定 Netty 工作線程數(shù)

  • autoRead 啟用請(qǐng)求正文自動(dòng)讀取

表 1. NettyHttpServerConfiguration 的配置屬性
屬性 類型 描述

micronaut.server.netty.child-options

java.util.Map

設(shè)置 Netty 子工作者選項(xiàng)。

micronaut.server.netty.options

java.util.Map

設(shè)置通道選項(xiàng)。

micronaut.server.netty.max-initial-line-length

int

設(shè)置 HTTP 請(qǐng)求的最大初始行長(zhǎng)度。默認(rèn)值 (4096)。

micronaut.server.netty.max-header-size

int

設(shè)置任何一個(gè)標(biāo)題的最大大小。默認(rèn)值 (8192)。

micronaut.server.netty.max-chunk-size

int

設(shè)置任何單個(gè)請(qǐng)求塊的最大大小。默認(rèn)值 (8192)。

micronaut.server.netty.max-h2c-upgrade-request-size

int

設(shè)置用于將連接升級(jí)到 HTTP2 明文 (h2c) 的 HTTP1.1 請(qǐng)求正文的最大大小。此初始請(qǐng)求無(wú)法流式傳輸,而是完全緩沖,因此默認(rèn)值 (8192) 相對(duì)較小。 <i>如果此值對(duì)于您的用例而言太小,請(qǐng)考慮使用空的初始“升級(jí)請(qǐng)求”(例如 {@code OPTIONS /}),或切換到普通 HTTP2。</i> <p> <i>不影響正常的 HTTP2 (TLS)。</i>

micronaut.server.netty.chunked-supported

boolean

設(shè)置是否支持分塊傳輸編碼。默認(rèn)值(真)。

micronaut.server.netty.validate-headers

boolean

設(shè)置是否驗(yàn)證傳入的標(biāo)頭。默認(rèn)值(真)。

micronaut.server.netty.initial-buffer-size

int

設(shè)置初始緩沖區(qū)大小。默認(rèn)值 (128)。

micronaut.server.netty.log-level

io.netty.handler.logging.LogLevel

設(shè)置 Netty 日志級(jí)別。

micronaut.server.netty.compression-threshold

int

設(shè)置請(qǐng)求主體必須的最小大小才能被壓縮。默認(rèn)值 (1024)。

micronaut.server.netty.compression-level

int

設(shè)置壓縮級(jí)別 (0-9)。默認(rèn)值 (6)。

micronaut.server.netty.use-native-transport

boolean

如果可用,設(shè)置是否使用 netty 的本地傳輸(epoll 或 kqueue)。默認(rèn)值(假)。

micronaut.server.netty.fallback-protocol

java.lang.String

設(shè)置通過(guò) ALPN 協(xié)商時(shí)要使用的回退協(xié)議。

micronaut.server.netty.keep-alive-on-server-error

boolean

是否發(fā)送連接在內(nèi)部服務(wù)器錯(cuò)誤時(shí)保持活動(dòng)狀態(tài)。默認(rèn)值({@value DEFAULT_KEEP_ALIVE_ON_SERVER_ERROR})。

micronaut.server.netty.pcap-logging-path-pattern

java.lang.String

用于記錄到 pcap 的傳入連接的路徑模式。這是一個(gè)不受支持的選項(xiàng):行為可能會(huì)改變,或者可能會(huì)完全消失,恕不另行通知!

micronaut.server.netty.listeners

java.util.List

設(shè)置顯式的 netty 偵聽器配置,或者 {@code null} 如果它們應(yīng)該是隱式的。

使用本機(jī)傳輸

與基于 NIO 的傳輸相比,本機(jī) Netty 傳輸添加特定于特定平臺(tái)的功能,產(chǎn)生更少的垃圾,并且通常提高性能。

要啟用本機(jī)傳輸,首先添加依賴項(xiàng):

對(duì)于 x86 上的 macOS:

 Gradle Maven 
runtimeOnly("io.netty:netty-transport-native-kqueue::osx-x86_64")
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-transport-native-kqueue</artifactId>
    <scope>runtime</scope>
    <classifier>osx-x86_64</classifier>
</dependency>

對(duì)于 M1 上的 macOS:

 Gradle Maven 
runtimeOnly("io.netty:netty-transport-native-kqueue::osx-aarch_64")
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-transport-native-kqueue</artifactId>
    <scope>runtime</scope>
    <classifier>osx-aarch_64</classifier>
</dependency>

對(duì)于 x86 上的 Linux:

 Gradle Maven 
runtimeOnly("io.netty:netty-transport-native-epoll::linux-x86_64")
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-transport-native-epoll</artifactId>
    <scope>runtime</scope>
    <classifier>linux-x86_64</classifier>
</dependency>

對(duì)于 ARM64 上的 Linux:

 Gradle Maven 
runtimeOnly("io.netty:netty-transport-native-epoll::linux-aarch_64")
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-transport-native-epoll</artifactId>
    <scope>runtime</scope>
    <classifier>linux-aarch_64</classifier>
</dependency>

然后將默認(rèn)事件循環(huán)組配置為更喜歡本機(jī)傳輸:

配置默認(rèn)事件循環(huán)以優(yōu)先使用本機(jī)傳輸

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.netty.event-loops.default.prefer-native-transport=true
micronaut:
  netty:
    event-loops:
      default:
        prefer-native-transport: true
[micronaut]
  [micronaut.netty]
    [micronaut.netty.event-loops]
      [micronaut.netty.event-loops.default]
        prefer-native-transport=true
micronaut {
  netty {
    eventLoops {
      'default' {
        preferNativeTransport = true
      }
    }
  }
}
{
  micronaut {
    netty {
      event-loops {
        default {
          prefer-native-transport = true
        }
      }
    }
  }
}
{
  "micronaut": {
    "netty": {
      "event-loops": {
        "default": {
          "prefer-native-transport": true
        }
      }
    }
  }
}

Netty 支持簡(jiǎn)單的采樣資源泄漏檢測(cè),以少量開銷為代價(jià)報(bào)告是否存在泄漏。您可以通過(guò)將屬性 netty.resource-leak-detector-level 設(shè)置為以下之一來(lái)禁用它或啟用更高級(jí)的檢測(cè):SIMPLE(默認(rèn))、DISABLED、PARANOID 或 ADVANCED。

配置服務(wù)器線程池

HTTP 服務(wù)器建立在 Netty 之上,Netty 被設(shè)計(jì)為事件循環(huán)模型中的非阻塞 I/O 工具包。

Netty worker 事件循環(huán)使用“默認(rèn)”命名的事件循環(huán)組。這可以通過(guò) micronaut.netty.event-loops.default 進(jìn)行配置。

micronaut.server.netty.worker 下的事件循環(huán)配置僅在事件循環(huán)組設(shè)置為不對(duì)應(yīng)于任何 micronaut.netty.event-loops 配置的名稱時(shí)使用。此行為已棄用,將在未來(lái)版本中刪除。將 micronaut.netty.event-loops.* 用于除了通過(guò) event-loop-group 設(shè)置名稱之外的任何事件循環(huán)組配置。這不適用于父事件循環(huán)配置(micronaut.server.netty.parent)。

表 1. Worker 的配置屬性
屬性 類型 描述

micronaut.server.netty.worker

NettyHttpServerConfiguration$Worker

設(shè)置 Worker 事件循環(huán)配置。

micronaut.server.netty.worker.event-loop-group

java.lang.String

設(shè)置要使用的名稱。

micronaut.server.netty.worker.threads

int

設(shè)置事件循環(huán)組的線程數(shù)。

micronaut.server.netty.worker.io-ratio

java.lang.Integer

設(shè)置 I/O 比率。

micronaut.server.netty.worker.executor

java.lang.String

設(shè)置執(zhí)行者的名字。

micronaut.server.netty.worker.prefer-native-transport

boolean

設(shè)置是否首選本地傳輸(如果可用)

micronaut.server.netty.worker.shutdown-quiet-period

java.time.Duration

設(shè)置關(guān)機(jī)靜默期

micronaut.server.netty.worker.shutdown-timeout

java.time.Duration

設(shè)置關(guān)機(jī)超時(shí)時(shí)間(必須>= shutdownQuietPeriod)

可以使用具有相同配置選項(xiàng)的 micronaut.server.netty.parent 配置父事件循環(huán)。

服務(wù)器也可以配置為使用不同的命名工作事件循環(huán):

為服務(wù)器使用不同的事件循環(huán)

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.server.netty.worker.event-loop-group=other
micronaut.netty.event-loops.other.num-threads=10
micronaut:
  server:
    netty:
      worker:
        event-loop-group: other
  netty:
    event-loops:
      other:
        num-threads: 10
[micronaut]
  [micronaut.server]
    [micronaut.server.netty]
      [micronaut.server.netty.worker]
        event-loop-group="other"
  [micronaut.netty]
    [micronaut.netty.event-loops]
      [micronaut.netty.event-loops.other]
        num-threads=10
micronaut {
  server {
    netty {
      worker {
        eventLoopGroup = "other"
      }
    }
  }
  netty {
    eventLoops {
      other {
        numThreads = 10
      }
    }
  }
}
{
  micronaut {
    server {
      netty {
        worker {
          event-loop-group = "other"
        }
      }
    }
    netty {
      event-loops {
        other {
          num-threads = 10
        }
      }
    }
  }
}
{
  "micronaut": {
    "server": {
      "netty": {
        "worker": {
          "event-loop-group": "other"
        }
      }
    },
    "netty": {
      "event-loops": {
        "other": {
          "num-threads": 10
        }
      }
    }
  }
}

線程數(shù)的默認(rèn)值是系統(tǒng)屬性 io.netty.eventLoopThreads 的值,或者如果未指定,則為可用處理器 x 2。

請(qǐng)參閱下表以配置事件循環(huán):

表 2. DefaultEventLoopGroupConfiguration 的配置屬性
屬性 類型 描述

micronaut.netty.event-loops.*.num-threads

int

micronaut.netty.event-loops.*.io-ratio

java.lang.Integer

micronaut.netty.event-loops.*.prefer-native-transport

boolean

micronaut.netty.event-loops.*.executor

java.lang.String

micronaut.netty.event-loops.*.shutdown-quiet-period

java.time.Duration

micronaut.netty.event-loops.*.shutdown-timeout

java.time.Duration

阻塞操作

在處理阻塞操作時(shí),Micronaut 默認(rèn)將阻塞操作轉(zhuǎn)移到未綁定的緩存 I/O 線程池。您可以使用名為 io 的 ExecutorConfiguration 配置 I/O 線程池。例如:

配置服務(wù)器 I/O 線程池

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.executors.io.type=fixed
micronaut.executors.io.nThreads=75
micronaut:
  executors:
    io:
      type: fixed
      nThreads: 75
[micronaut]
  [micronaut.executors]
    [micronaut.executors.io]
      type="fixed"
      nThreads=75
micronaut {
  executors {
    io {
      type = "fixed"
      nThreads = 75
    }
  }
}
{
  micronaut {
    executors {
      io {
        type = "fixed"
        nThreads = 75
      }
    }
  }
}
{
  "micronaut": {
    "executors": {
      "io": {
        "type": "fixed",
        "nThreads": 75
      }
    }
  }
}

上面的配置創(chuàng)建了一個(gè)有 75 個(gè)線程的固定線程池。

@Blocking

您可以使用 @Blocking 注釋將方法標(biāo)記為阻塞。

如果將 micronaut.server.thread-selection 設(shè)置為 AUTO,Micronaut 框架會(huì)將使用 @Blocking 注釋的方法的執(zhí)行卸載到 IO 線程池(請(qǐng)參閱:TaskExecutors)。

@Blocking 僅在您使用自動(dòng)線程選擇時(shí)才有效。自 Micronaut 2.0 以來(lái),Micronaut 框架默認(rèn)為手動(dòng)線程選擇。我們推薦使用@ExecuteOn 注解在不同的線程池上執(zhí)行阻塞操作。 @ExecutesOn 適用于手動(dòng)和自動(dòng)線程選擇。

Micronaut 框架在某些地方內(nèi)部使用了@Blocking:

Blocking 類型 描述

BlockingHttpClient

用于測(cè)試,為 HttpClient 操作的子集提供阻塞版本。

IOUtils

以阻塞方式讀取 BufferedReader 的內(nèi)容,并將其作為字符串返回。

BootstrapPropertySourceLocator

解析當(dāng)前環(huán)境的遠(yuǎn)程或本地 PropertySource 實(shí)例。

Micronaut Data 還在內(nèi)部利用 @Blocking 進(jìn)行一些事務(wù)操作、CRUD 攔截器和存儲(chǔ)庫(kù)。

配置 Netty 客戶端管道

您可以通過(guò)編寫偵聽注冊(cè)表創(chuàng)建的 Bean 事件偵聽器來(lái)自定義 Netty 客戶端管道。

ChannelPipelineCustomizer 接口為各種處理程序 Micronaut 寄存器的名稱定義常量。

作為示例,以下代碼示例演示了注冊(cè) Logbook 庫(kù),其中包括用于執(zhí)行請(qǐng)求和響應(yīng)日志記錄的其他 Netty 處理程序:

為 Logbook 定制 Netty 服務(wù)器管道

 Java Groovy  Kotlin 
import io.micronaut.context.annotation.Requires;
import io.micronaut.context.event.BeanCreatedEvent;
import io.micronaut.context.event.BeanCreatedEventListener;
import io.micronaut.http.client.netty.NettyClientCustomizer;
import io.micronaut.http.netty.channel.ChannelPipelineCustomizer;
import io.netty.channel.Channel;
import io.netty.channel.ChannelPipeline;
import jakarta.inject.Singleton;
import org.zalando.logbook.Logbook;
import org.zalando.logbook.netty.LogbookClientHandler;

@Requires(beans = Logbook.class)
@Singleton
public class LogbookNettyClientCustomizer
    implements BeanCreatedEventListener<NettyClientCustomizer.Registry> { // (1)
    private final Logbook logbook;

    public LogbookNettyClientCustomizer(Logbook logbook) {
        this.logbook = logbook;
    }

    @Override
    public NettyClientCustomizer.Registry onCreated(
        BeanCreatedEvent<NettyClientCustomizer.Registry> event) {

        NettyClientCustomizer.Registry registry = event.getBean();
        registry.register(new Customizer(null)); // (2)
        return registry;
    }

    private class Customizer implements NettyClientCustomizer { // (3)
        private final Channel channel;

        Customizer(Channel channel) {
            this.channel = channel;
        }

        @Override
        public NettyClientCustomizer specializeForChannel(Channel channel, ChannelRole role) {
            return new Customizer(channel); // (4)
        }

        @Override
        public void onStreamPipelineBuilt() {
            channel.pipeline().addLast( // (5)
                "logbook",
                new LogbookClientHandler(logbook)
            );
        }
    }
}
import io.micronaut.context.event.BeanCreatedEvent
import io.micronaut.context.event.BeanCreatedEventListener
import io.micronaut.http.client.netty.NettyClientCustomizer
import io.netty.channel.Channel
import jakarta.inject.Singleton
import org.zalando.logbook.Logbook
import org.zalando.logbook.netty.LogbookClientHandler


@Requires(beans = Logbook.class)
@Singleton
class LogbookNettyClientCustomizer
        implements BeanCreatedEventListener<NettyClientCustomizer.Registry> { // (1)
    private final Logbook logbook;

    LogbookNettyClientCustomizer(Logbook logbook) {
        this.logbook = logbook
    }

    @Override
    NettyClientCustomizer.Registry onCreated(
            BeanCreatedEvent<NettyClientCustomizer.Registry> event) {

        NettyClientCustomizer.Registry registry = event.getBean()
        registry.register(new Customizer(null)) // (2)
        return registry
    }

    private class Customizer implements NettyClientCustomizer { // (3)
        private final Channel channel

        Customizer(Channel channel) {
            this.channel = channel
        }

        @Override
        NettyClientCustomizer specializeForChannel(Channel channel, ChannelRole role) {
            return new Customizer(channel) // (4)
        }

        @Override
        void onStreamPipelineBuilt() {
            channel.pipeline().addLast( // (5)
                    "logbook",
                    new LogbookClientHandler(logbook)
            )
        }
    }
}
import io.micronaut.context.annotation.Requires
import io.micronaut.context.event.BeanCreatedEvent
import io.micronaut.context.event.BeanCreatedEventListener
import io.micronaut.http.client.netty.NettyClientCustomizer
import io.micronaut.http.client.netty.NettyClientCustomizer.ChannelRole
import io.netty.channel.Channel
import jakarta.inject.Singleton
import org.zalando.logbook.Logbook
import org.zalando.logbook.netty.LogbookClientHandler

@Requires(beans = [Logbook::class])
@Singleton
class LogbookNettyClientCustomizer(private val logbook: Logbook) :
    BeanCreatedEventListener<NettyClientCustomizer.Registry> { // (1)

    override fun onCreated(event: BeanCreatedEvent<NettyClientCustomizer.Registry>): NettyClientCustomizer.Registry {
        val registry = event.bean
        registry.register(Customizer(null)) // (2)
        return registry
    }

    private inner class Customizer constructor(private val channel: Channel?) :
        NettyClientCustomizer { // (3)

        override fun specializeForChannel(channel: Channel, role: ChannelRole) = Customizer(channel) // (4)

        override fun onStreamPipelineBuilt() {
            channel!!.pipeline().addLast( // (5)
                "logbook",
                LogbookClientHandler(logbook)
            )
        }
    }
}
  1. LogbookNettyClientCustomizer 監(jiān)聽一個(gè) Registry 并且需要一個(gè) Logbook bean 的定義

  2. 根定制器在沒有通道的情況下初始化并注冊(cè)

  3. 實(shí)際的定制器實(shí)現(xiàn)了 NettyClientCustomizer

  4. 創(chuàng)建新頻道時(shí),會(huì)為該頻道創(chuàng)建一個(gè)新的專用定制器

  5. 當(dāng)客戶端發(fā)出流管道已完全構(gòu)建的信號(hào)時(shí),將注冊(cè)日志處理程序

Logbook 有一個(gè)主要錯(cuò)誤,限制了它在 netty 中的實(shí)用性。

配置 Netty 服務(wù)器管道

您可以通過(guò)編寫監(jiān)聽 Registry 創(chuàng)建的 Bean 事件監(jiān)聽器來(lái)自定義 Netty 服務(wù)器管道。

ChannelPipelineCustomizer 接口為各種處理程序 Micronaut 寄存器的名稱定義常量。

作為示例,以下代碼示例演示了注冊(cè) Logbook 庫(kù),其中包括用于執(zhí)行請(qǐng)求和響應(yīng)日志記錄的其他 Netty 處理程序:

為 Logbook 定制 Netty 服務(wù)器管道

 Java Groovy  Kotlin 
import io.micronaut.context.annotation.Requires;
import io.micronaut.context.event.BeanCreatedEvent;
import io.micronaut.context.event.BeanCreatedEventListener;
import io.micronaut.http.netty.channel.ChannelPipelineCustomizer;
import io.micronaut.http.server.netty.NettyServerCustomizer;
import io.netty.channel.Channel;
import org.zalando.logbook.Logbook;
import org.zalando.logbook.netty.LogbookServerHandler;

import jakarta.inject.Singleton;

@Requires(beans = Logbook.class)
@Singleton
public class LogbookNettyServerCustomizer
    implements BeanCreatedEventListener<NettyServerCustomizer.Registry> { // (1)
    private final Logbook logbook;

    public LogbookNettyServerCustomizer(Logbook logbook) {
        this.logbook = logbook;
    }

    @Override
    public NettyServerCustomizer.Registry onCreated(
        BeanCreatedEvent<NettyServerCustomizer.Registry> event) {

        NettyServerCustomizer.Registry registry = event.getBean();
        registry.register(new Customizer(null)); // (2)
        return registry;
    }

    private class Customizer implements NettyServerCustomizer { // (3)
        private final Channel channel;

        Customizer(Channel channel) {
            this.channel = channel;
        }

        @Override
        public NettyServerCustomizer specializeForChannel(Channel channel, ChannelRole role) {
            return new Customizer(channel); // (4)
        }

        @Override
        public void onStreamPipelineBuilt() {
            channel.pipeline().addBefore( // (5)
                ChannelPipelineCustomizer.HANDLER_HTTP_STREAM,
                "logbook",
                new LogbookServerHandler(logbook)
            );
        }
    }
}
import io.micronaut.context.annotation.Requires
import io.micronaut.context.event.BeanCreatedEvent
import io.micronaut.context.event.BeanCreatedEventListener
import io.micronaut.http.netty.channel.ChannelPipelineCustomizer
import io.micronaut.http.server.netty.NettyServerCustomizer
import io.netty.channel.Channel
import org.zalando.logbook.Logbook
import org.zalando.logbook.netty.LogbookServerHandler

import jakarta.inject.Singleton

@Requires(beans = Logbook.class)
@Singleton
class LogbookNettyServerCustomizer
        implements BeanCreatedEventListener<NettyServerCustomizer.Registry> { // (1)
    private final Logbook logbook;

    LogbookNettyServerCustomizer(Logbook logbook) {
        this.logbook = logbook
    }

    @Override
    NettyServerCustomizer.Registry onCreated(
            BeanCreatedEvent<NettyServerCustomizer.Registry> event) {

        NettyServerCustomizer.Registry registry = event.getBean()
        registry.register(new Customizer(null)) // (2)
        return registry
    }

    private class Customizer implements NettyServerCustomizer { // (3)
        private final Channel channel

        Customizer(Channel channel) {
            this.channel = channel
        }

        @Override
        NettyServerCustomizer specializeForChannel(Channel channel, ChannelRole role) {
            return new Customizer(channel) // (4)
        }

        @Override
        void onStreamPipelineBuilt() {
            channel.pipeline().addBefore( // (5)
                    ChannelPipelineCustomizer.HANDLER_HTTP_STREAM,
                    "logbook",
                    new LogbookServerHandler(logbook)
            )
        }
    }
}
import io.micronaut.context.annotation.Requires
import io.micronaut.context.event.BeanCreatedEvent
import io.micronaut.context.event.BeanCreatedEventListener
import io.micronaut.http.netty.channel.ChannelPipelineCustomizer
import io.micronaut.http.server.netty.NettyServerCustomizer
import io.micronaut.http.server.netty.NettyServerCustomizer.ChannelRole
import io.netty.channel.Channel
import jakarta.inject.Singleton
import org.zalando.logbook.Logbook
import org.zalando.logbook.netty.LogbookServerHandler

@Requires(beans = [Logbook::class])
@Singleton
class LogbookNettyServerCustomizer(private val logbook: Logbook) :
    BeanCreatedEventListener<NettyServerCustomizer.Registry> { // (1)

    override fun onCreated(event: BeanCreatedEvent<NettyServerCustomizer.Registry>): NettyServerCustomizer.Registry {
        val registry = event.bean
        registry.register(Customizer(null)) // (2)
        return registry
    }

    private inner class Customizer constructor(private val channel: Channel?) :
        NettyServerCustomizer { // (3)

        override fun specializeForChannel(channel: Channel, role: ChannelRole) = Customizer(channel) // (4)

        override fun onStreamPipelineBuilt() {
            channel!!.pipeline().addBefore( // (5)
                ChannelPipelineCustomizer.HANDLER_HTTP_STREAM,
                "logbook",
                LogbookServerHandler(logbook)
            )
        }
    }
}
  1. LogbookNettyServerCustomizer 監(jiān)聽一個(gè) Registry 并且需要一個(gè) Logbook bean 的定義

  2. 根定制器在沒有通道的情況下初始化并注冊(cè)

  3. 實(shí)際的定制器實(shí)現(xiàn)了 NettyServerCustomizer

  4. 創(chuàng)建新頻道時(shí),會(huì)為該頻道創(chuàng)建一個(gè)新的專用定制器

  5. 當(dāng)服務(wù)器發(fā)出流管道已完全構(gòu)建的信號(hào)時(shí),將注冊(cè)日志處理程序

Logbook 有一個(gè)主要錯(cuò)誤,限制了它在 netty 中的實(shí)用性。

高級(jí)偵聽器配置

您也可以手動(dòng)指定每個(gè)偵聽器,而不是配置單個(gè)端口。

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.server.netty.listeners.httpListener.host=127.0.0.1
micronaut.server.netty.listeners.httpListener.port=8086
micronaut.server.netty.listeners.httpListener.ssl=false
micronaut.server.netty.listeners.httpsListener.port=8087
micronaut.server.netty.listeners.httpsListener.ssl=true
micronaut:
  server:
    netty:
      listeners:
        httpListener:
          host: 127.0.0.1
          port: 8086
          ssl: false
        httpsListener:
          port: 8087
          ssl: true
[micronaut]
  [micronaut.server]
    [micronaut.server.netty]
      [micronaut.server.netty.listeners]
        [micronaut.server.netty.listeners.httpListener]
          host="127.0.0.1"
          port=8086
          ssl=false
        [micronaut.server.netty.listeners.httpsListener]
          port=8087
          ssl=true
micronaut {
  server {
    netty {
      listeners {
        httpListener {
          host = "127.0.0.1"
          port = 8086
          ssl = false
        }
        httpsListener {
          port = 8087
          ssl = true
        }
      }
    }
  }
}
{
  micronaut {
    server {
      netty {
        listeners {
          httpListener {
            host = "127.0.0.1"
            port = 8086
            ssl = false
          }
          httpsListener {
            port = 8087
            ssl = true
          }
        }
      }
    }
  }
}
{
  "micronaut": {
    "server": {
      "netty": {
        "listeners": {
          "httpListener": {
            "host": "127.0.0.1",
            "port": 8086,
            "ssl": false
          },
          "httpsListener": {
            "port": 8087,
            "ssl": true
          }
        }
      }
    }
  }
}
  • httpListener 是監(jiān)聽器名稱,可以是任意值

  • host 是可選的,默認(rèn)情況下綁定到所有接口

如果您手動(dòng)指定監(jiān)聽器,其他配置如 micronaut.server.port 將被忽略。

可以為每個(gè)偵聽器單獨(dú)啟用或禁用 SSL。啟用后,SSL 將按上述方式配置。

嵌入式服務(wù)器還支持使用 netty 綁定到 unix 域套接字。這需要以下依賴項(xiàng):

 Gradle Maven 
implementation("io.netty:netty-transport-native-unix-common")
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-transport-native-unix-common</artifactId>
</dependency>

服務(wù)器還必須配置為使用本地傳輸(epoll 或 kqueue)。

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.server.netty.listeners.unixListener.family=UNIX
micronaut.server.netty.listeners.unixListener.path=/run/micronaut.socket
micronaut.server.netty.listeners.unixListener.ssl=true
micronaut:
  server:
    netty:
      listeners:
        unixListener:
          family: UNIX
          path: /run/micronaut.socket
          ssl: true
[micronaut]
  [micronaut.server]
    [micronaut.server.netty]
      [micronaut.server.netty.listeners]
        [micronaut.server.netty.listeners.unixListener]
          family="UNIX"
          path="/run/micronaut.socket"
          ssl=true
micronaut {
  server {
    netty {
      listeners {
        unixListener {
          family = "UNIX"
          path = "/run/micronaut.socket"
          ssl = true
        }
      }
    }
  }
}
{
  micronaut {
    server {
      netty {
        listeners {
          unixListener {
            family = "UNIX"
            path = "/run/micronaut.socket"
            ssl = true
          }
        }
      }
    }
  }
}
{
  "micronaut": {
    "server": {
      "netty": {
        "listeners": {
          "unixListener": {
            "family": "UNIX",
            "path": "/run/micronaut.socket",
            "ssl": true
          }
        }
      }
    }
  }
}
  • unixListener 是監(jiān)聽器名稱,可以是任意值

要使用抽象域套接字而不是普通套接字,請(qǐng)?jiān)诼窂角凹由?nbsp;NUL 字符,例如“\0/run/micronaut.socket”

配置 CORS

Micronaut 開箱即用地支持 CORS(跨源資源共享)。默認(rèn)情況下,拒絕 CORS 請(qǐng)求。

CORS 通過(guò)配置

要啟用 CORS 請(qǐng)求處理,請(qǐng)修改應(yīng)用程序配置文件中的配置:

CORS 配置示例

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.server.cors.enabled=true
micronaut:
  server:
    cors:
      enabled: true
[micronaut]
  [micronaut.server]
    [micronaut.server.cors]
      enabled=true
micronaut {
  server {
    cors {
      enabled = true
    }
  }
}
{
  micronaut {
    server {
      cors {
        enabled = true
      }
    }
  }
}
{
  "micronaut": {
    "server": {
      "cors": {
        "enabled": true
      }
    }
  }
}

通過(guò)僅啟用 CORS 處理,采用“完全開放”策略,允許來(lái)自任何來(lái)源的請(qǐng)求。

要更改所有來(lái)源或特定來(lái)源的設(shè)置,請(qǐng)更改配置以提供一個(gè)或多個(gè)“配置”。通過(guò)提供任何配置,不配置默認(rèn)的“全開”配置。

CORS 配置

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.server.cors.enabled=true
micronaut.server.cors.configurations.all=...
micronaut.server.cors.configurations.web=...
micronaut.server.cors.configurations.mobile=...
micronaut:
  server:
    cors:
      enabled: true
      configurations:
        all:
          ...
        web:
          ...
        mobile:
          ...
[micronaut]
  [micronaut.server]
    [micronaut.server.cors]
      enabled=true
      [micronaut.server.cors.configurations]
        all="..."
        web="..."
        mobile="..."
micronaut {
  server {
    cors {
      enabled = true
      configurations {
        all = "..."
        web = "..."
        mobile = "..."
      }
    }
  }
}
{
  micronaut {
    server {
      cors {
        enabled = true
        configurations {
          all = "..."
          web = "..."
          mobile = "..."
        }
      }
    }
  }
}
{
  "micronaut": {
    "server": {
      "cors": {
        "enabled": true,
        "configurations": {
          "all": "...",
          "web": "...",
          "mobile": "..."
        }
      }
    }
  }
}

在上面的示例中,提供了三種配置。它們的名稱(all、web、mobile)并不重要,在 Micronaut 中沒有任何意義。它們的存在純粹是為了能夠輕松識(shí)別配置的預(yù)期用戶。

相同的配置屬性可以應(yīng)用于每個(gè)配置。有關(guān)可以定義的屬性,請(qǐng)參閱 CorsOriginConfiguration。提供的每個(gè)配置的值將默認(rèn)為相應(yīng)字段的默認(rèn)值。

當(dāng)發(fā)出 CORS 請(qǐng)求時(shí),將在配置中搜索完全匹配或通過(guò)正則表達(dá)式匹配請(qǐng)求源的允許源。

Allowed Origins

要允許給定配置的任何來(lái)源,請(qǐng)不要在您的配置中包含 allowedOrigins 鍵。

對(duì)于多個(gè)有效來(lái)源,將配置的 allowedOrigins 鍵設(shè)置為字符串列表。每個(gè)值可以是靜態(tài)值 (http://www.foo.com) 或正則表達(dá)式 (^http(|s)://www\.google\.com$)。

正則表達(dá)式被傳遞給 Pattern#compile 并與 Matcher#matches 的請(qǐng)求源進(jìn)行比較。

示例 CORS 配置

 Properties Yaml Toml Groovy  Hocon  JSON 
micronaut.server.cors.enabled=true
micronaut.server.cors.configurations.web.allowedOrigins[0]=http://foo.com
micronaut.server.cors.configurations.web.allowedOrigins[1]=^http(|s):\/\/www\.google\.com$
micronaut:
  server:
    cors:
      enabled: true
      configurations:
        web:
          allowedOrigins:
            - http://foo.com
            - ^http(|s):\/\/www\.google\.com$
[micronaut]
  [micronaut.server]
    [micronaut.server.cors]
      enabled=true
      [micronaut.server.cors.configurations]
        [micronaut.server.cors.configurations.web]
          allowedOrigins=[
            "http://foo.com",
            "^http(|s):\\/\\/www\\.google\\.com$"
          ]
micronaut {
  server {
    cors {
      enabled = true
      configurations {
        web {
          allowedOrigins = ["http://foo.com", "^http(|s):\\/\\/www\\.google\\.com$"]
        }
      }
    }
  }
}
{
  micronaut {
    server {
      cors {
        enabled = true
        configurations {
          web {
            allowedOrigins = ["http://foo.com", "^http(|s):\\/\\/www\\.google\\.com$"]
          }
        }
      }
    }
  }
}
{
  "micronaut": {
    "server": {
      "cors": {
        "enabled": true,
        "configurations": {
          "web": {
            "allowedOrigins": ["http://foo.com", "^http(|s):\\/\\/www\\.google\\.com$"]
          }
        }
      }
    }
  }
}

Allowed Methods

要允許給定配置的任何請(qǐng)求方法,請(qǐng)不要在您的配置中包含 allowedMethods 鍵。

對(duì)于多個(gè)允許的方法,將配置的 allowedMethods 鍵設(shè)置為字符串列表。

示例 CORS 配置

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.server.cors.enabled=true
micronaut.server.cors.configurations.web.allowedOrigins[0]=http://foo.com
micronaut.server.cors.configurations.web.allowedOrigins[1]=^http(|s):\/\/www\.google\.com$
micronaut:
  server:
    cors:
      enabled: true
      configurations:
        web:
          allowedOrigins:
            - http://foo.com
            - ^http(|s):\/\/www\.google\.com$
[micronaut]
  [micronaut.server]
    [micronaut.server.cors]
      enabled=true
      [micronaut.server.cors.configurations]
        [micronaut.server.cors.configurations.web]
          allowedOrigins=[
            "http://foo.com",
            "^http(|s):\\/\\/www\\.google\\.com$"
          ]
micronaut {
  server {
    cors {
      enabled = true
      configurations {
        web {
          allowedOrigins = ["http://foo.com", "^http(|s):\\/\\/www\\.google\\.com$"]
        }
      }
    }
  }
}
{
  micronaut {
    server {
      cors {
        enabled = true
        configurations {
          web {
            allowedOrigins = ["http://foo.com", "^http(|s):\\/\\/www\\.google\\.com$"]
          }
        }
      }
    }
  }
}
{
  "micronaut": {
    "server": {
      "cors": {
        "enabled": true,
        "configurations": {
          "web": {
            "allowedOrigins": ["http://foo.com", "^http(|s):\\/\\/www\\.google\\.com$"]
          }
        }
      }
    }
  }
}

Allowed Headers

要允許給定配置的任何請(qǐng)求標(biāo)頭,請(qǐng)不要在您的配置中包含 allowedHeaders 鍵。

對(duì)于多個(gè)允許的標(biāo)頭,將配置的 allowedHeaders 鍵設(shè)置為字符串列表。

示例 CORS 配置

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.server.cors.enabled=true
micronaut.server.cors.configurations.web.allowedHeaders[0]=Content-Type
micronaut.server.cors.configurations.web.allowedHeaders[1]=Authorization
micronaut:
  server:
    cors:
      enabled: true
      configurations:
        web:
          allowedHeaders:
            - Content-Type
            - Authorization
[micronaut]
  [micronaut.server]
    [micronaut.server.cors]
      enabled=true
      [micronaut.server.cors.configurations]
        [micronaut.server.cors.configurations.web]
          allowedHeaders=[
            "Content-Type",
            "Authorization"
          ]
micronaut {
  server {
    cors {
      enabled = true
      configurations {
        web {
          allowedHeaders = ["Content-Type", "Authorization"]
        }
      }
    }
  }
}
{
  micronaut {
    server {
      cors {
        enabled = true
        configurations {
          web {
            allowedHeaders = ["Content-Type", "Authorization"]
          }
        }
      }
    }
  }
}
{
  "micronaut": {
    "server": {
      "cors": {
        "enabled": true,
        "configurations": {
          "web": {
            "allowedHeaders": ["Content-Type", "Authorization"]
          }
        }
      }
    }
  }
}

Exposed Headers

要配置在通過(guò) Access-Control-Expose-Headers 標(biāo)頭響應(yīng) CORS 請(qǐng)求時(shí)發(fā)送的標(biāo)頭,請(qǐng)?jiān)谀呐渲弥邪?nbsp;exposedHeaders 鍵的字符串列表。默認(rèn)情況下沒有公開。

示例 CORS 配置

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.server.cors.enabled=true
micronaut.server.cors.configurations.web.exposedHeaders[0]=Content-Type
micronaut.server.cors.configurations.web.exposedHeaders[1]=Authorization
micronaut:
  server:
    cors:
      enabled: true
      configurations:
        web:
          exposedHeaders:
            - Content-Type
            - Authorization
[micronaut]
  [micronaut.server]
    [micronaut.server.cors]
      enabled=true
      [micronaut.server.cors.configurations]
        [micronaut.server.cors.configurations.web]
          exposedHeaders=[
            "Content-Type",
            "Authorization"
          ]
micronaut {
  server {
    cors {
      enabled = true
      configurations {
        web {
          exposedHeaders = ["Content-Type", "Authorization"]
        }
      }
    }
  }
}
{
  micronaut {
    server {
      cors {
        enabled = true
        configurations {
          web {
            exposedHeaders = ["Content-Type", "Authorization"]
          }
        }
      }
    }
  }
}
{
  "micronaut": {
    "server": {
      "cors": {
        "enabled": true,
        "configurations": {
          "web": {
            "exposedHeaders": ["Content-Type", "Authorization"]
          }
        }
      }
    }
  }
}

Allow Credentials

CORS 請(qǐng)求默認(rèn)允許憑據(jù)。要禁止憑據(jù),請(qǐng)將 allowCredentials 選項(xiàng)設(shè)置為 false。

示例 CORS 配置

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.server.cors.enabled=true
micronaut.server.cors.configurations.web.allowCredentials=false
micronaut:
  server:
    cors:
      enabled: true
      configurations:
        web:
          allowCredentials: false
[micronaut]
  [micronaut.server]
    [micronaut.server.cors]
      enabled=true
      [micronaut.server.cors.configurations]
        [micronaut.server.cors.configurations.web]
          allowCredentials=false
micronaut {
  server {
    cors {
      enabled = true
      configurations {
        web {
          allowCredentials = false
        }
      }
    }
  }
}
{
  micronaut {
    server {
      cors {
        enabled = true
        configurations {
          web {
            allowCredentials = false
          }
        }
      }
    }
  }
}
{
  "micronaut": {
    "server": {
      "cors": {
        "enabled": true,
        "configurations": {
          "web": {
            "allowCredentials": false
          }
        }
      }
    }
  }
}

Max Age

預(yù)檢請(qǐng)求可以緩存的默認(rèn)最長(zhǎng)期限為 30 分鐘。要更改該行為,請(qǐng)以秒為單位指定一個(gè)值。

示例 CORS 配置

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.server.cors.enabled=true
micronaut.server.cors.configurations.web.maxAge=3600
micronaut:
  server:
    cors:
      enabled: true
      configurations:
        web:
          maxAge: 3600 # 1 hour
[micronaut]
  [micronaut.server]
    [micronaut.server.cors]
      enabled=true
      [micronaut.server.cors.configurations]
        [micronaut.server.cors.configurations.web]
          maxAge=3600
micronaut {
  server {
    cors {
      enabled = true
      configurations {
        web {
          maxAge = 3600
        }
      }
    }
  }
}
{
  micronaut {
    server {
      cors {
        enabled = true
        configurations {
          web {
            maxAge = 3600
          }
        }
      }
    }
  }
}
{
  "micronaut": {
    "server": {
      "cors": {
        "enabled": true,
        "configurations": {
          "web": {
            "maxAge": 3600
          }
        }
      }
    }
  }
}

Multiple Header Values

默認(rèn)情況下,當(dāng)一個(gè)標(biāo)頭有多個(gè)值時(shí),將發(fā)送多個(gè)標(biāo)頭,每個(gè)標(biāo)頭都有一個(gè)值。通過(guò)設(shè)置配置選項(xiàng),可以更改行為以發(fā)送帶有逗號(hào)分隔值列表的單個(gè)標(biāo)頭。

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.server.cors.single-header=true
micronaut:
  server:
    cors:
      single-header: true
[micronaut]
  [micronaut.server]
    [micronaut.server.cors]
      single-header=true
micronaut {
  server {
    cors {
      singleHeader = true
    }
  }
}
{
  micronaut {
    server {
      cors {
        single-header = true
      }
    }
  }
}
{
  "micronaut": {
    "server": {
      "cors": {
        "single-header": true
      }
    }
  }
}

Securing the Server with HTTPS

Micronaut 開箱即用地支持 HTTPS。默認(rèn)情況下 HTTPS 被禁用,所有請(qǐng)求都使用 HTTP 服務(wù)。要啟用 HTTPS 支持,請(qǐng)修改您的配置。例如:

HTTPS 配置示例

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.server.ssl.enabled=true
micronaut.server.ssl.buildSelfSigned=true
micronaut:
  server:
    ssl:
      enabled: true
      buildSelfSigned: true
[micronaut]
  [micronaut.server]
    [micronaut.server.ssl]
      enabled=true
      buildSelfSigned=true
micronaut {
  server {
    ssl {
      enabled = true
      buildSelfSigned = true
    }
  }
}
{
  micronaut {
    server {
      ssl {
        enabled = true
        buildSelfSigned = true
      }
    }
  }
}
{
  "micronaut": {
    "server": {
      "ssl": {
        "enabled": true,
        "buildSelfSigned": true
      }
    }
  }
}
  • Micronaut 將創(chuàng)建一個(gè)自簽名證書。

默認(rèn)情況下,支持 HTTPS 的 Micronaut 在端口 8443 上啟動(dòng),但您可以使用屬性 micronaut.server.ssl.port 更改端口。

為了生成自簽名證書,Micronaut HTTP 服務(wù)器將使用 netty。 Netty 使用兩種方法之一來(lái)生成證書。

如果您使用預(yù)先生成的證書(出于安全考慮,您應(yīng)該這樣做),則不需要執(zhí)行這些步驟。

  • Netty 可以使用 JDK 內(nèi)部的 sun.security.x509 包。在較新的 JDK 版本上,此包受到限制,可能無(wú)法使用。您可能需要添加 --add-exports=java.base/sun.security.x509=ALL-UNNAMED 作為 VM 參數(shù)。

  • 或者,netty 將使用 Bouncy Castle BCPKIX API。這需要一個(gè)額外的依賴:

 Gradle Maven 
implementation("org.bouncycastle:bcpkix-jdk15on")
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk15on</artifactId>
</dependency>

此配置將在瀏覽器中生成警告。


使用有效的 x509 證書

也可以將 Micronaut 配置為使用現(xiàn)有的有效 x509 證書,例如使用 Let's Encrypt 創(chuàng)建的證書。您將需要 server.crt 和 server.key 文件并將它們轉(zhuǎn)換為 PKCS #12 文件。

$ openssl pkcs12 -export \
                 -in server.crt \ (1)
                 -inkey server.key \ (2)
                 -out server.p12 \ (3)
                 -name someAlias \ (4)
                 -chain -CAfile ca.crt -caname root
  1. 原始 server.crt 文件

  2. 原始 server.key 文件

  3. 要?jiǎng)?chuàng)建的 server.p12 文件

  4. 證書的別名

在創(chuàng)建 server.p12 文件期間,有必要定義一個(gè)密碼,稍后在 Micronaut 中使用證書時(shí)將需要該密碼。

現(xiàn)在修改你的配置:

HTTPS 配置示例

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.ssl.enabled=true
micronaut.ssl.key-store.path=classpath:server.p12
micronaut.ssl.key-store.password=mypassword
micronaut.ssl.key-store.type=PKCS12
micronaut:
  ssl:
    enabled: true
    key-store:
      path: classpath:server.p12
      password: mypassword
      type: PKCS12
[micronaut]
  [micronaut.ssl]
    enabled=true
    [micronaut.ssl.key-store]
      path="classpath:server.p12"
      password="mypassword"
      type="PKCS12"
micronaut {
  ssl {
    enabled = true
    keyStore {
      path = "classpath:server.p12"
      password = "mypassword"
      type = "PKCS12"
    }
  }
}
{
  micronaut {
    ssl {
      enabled = true
      key-store {
        path = "classpath:server.p12"
        password = "mypassword"
        type = "PKCS12"
      }
    }
  }
}
{
  "micronaut": {
    "ssl": {
      "enabled": true,
      "key-store": {
        "path": "classpath:server.p12",
        "password": "mypassword",
        "type": "PKCS12"
      }
    }
  }
}
  • 指定 p12 文件路徑。它也可以被引用為 file:/path/to/the/file

  • 還要提供導(dǎo)出期間定義的密碼

使用此配置,如果我們啟動(dòng) Micronaut 并連接到 https://localhost:8443,我們?nèi)匀粫?huì)在瀏覽器中看到警告,但如果我們檢查證書,我們可以檢查它是否是由 Let's Encrypt 生成的。


最后,我們可以通過(guò)在 /etc/hosts 文件中為域添加別名來(lái)測(cè)試證書對(duì)瀏覽器是否有效:

$ cat /etc/hosts
...
127.0.0.1   my-domain.org
...

現(xiàn)在我們可以連接到 https://my-domain.org:8443:


使用 Java 密鑰庫(kù) (JKS)

不建議使用這種類型的證書,因?yàn)楦袷绞菍S械?nbsp;- 首選 PKCS12 格式。不管怎樣,Micronaut 也支持它。

將 p12 證書轉(zhuǎn)換為 JKS 證書:

$ keytool -importkeystore \
          -deststorepass newPassword -destkeypass newPassword \ (1)
          -destkeystore server.keystore \ (2)
          -srckeystore server.p12 -srcstoretype PKCS12 -srcstorepass mypassword \ (3)
          -alias someAlias (4)
  1. 有必要為密鑰庫(kù)定義密碼

  2. 要?jiǎng)?chuàng)建的文件

  3. 之前創(chuàng)建的PKCS12文件,以及創(chuàng)建時(shí)定義的密碼

  4. 之前使用的別名

如果 srcstorepass 或別名與 p12 文件中定義的不同,轉(zhuǎn)換將失敗。

現(xiàn)在修改你的配置:

HTTPS 配置示例

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.ssl.enabled=true
micronaut.ssl.key-store.path=classpath:server.keystore
micronaut.ssl.key-store.password=newPassword
micronaut.ssl.key-store.type=JKS
micronaut:
  ssl:
    enabled: true
    key-store:
      path: classpath:server.keystore
      password: newPassword
      type: JKS
[micronaut]
  [micronaut.ssl]
    enabled=true
    [micronaut.ssl.key-store]
      path="classpath:server.keystore"
      password="newPassword"
      type="JKS"
micronaut {
  ssl {
    enabled = true
    keyStore {
      path = "classpath:server.keystore"
      password = "newPassword"
      type = "JKS"
    }
  }
}
{
  micronaut {
    ssl {
      enabled = true
      key-store {
        path = "classpath:server.keystore"
        password = "newPassword"
        type = "JKS"
      }
    }
  }
}
{
  "micronaut": {
    "ssl": {
      "enabled": true,
      "key-store": {
        "path": "classpath:server.keystore",
        "password": "newPassword",
        "type": "JKS"
      }
    }
  }
}

啟動(dòng) Micronaut,應(yīng)用程序?qū)⑹褂妹荑€庫(kù)中的證書在 https://localhost:8443 上運(yùn)行。

刷新/重新加載 HTTPS 證書

在 HTTPS 證書過(guò)期后保持最新狀態(tài)可能是一個(gè)挑戰(zhàn)。一個(gè)很好的解決方案是自動(dòng)證書管理環(huán)境 (ACME) 和 Micronaut ACME 模塊,它支持從證書頒發(fā)機(jī)構(gòu)自動(dòng)刷新證書。

如果無(wú)法使用證書頒發(fā)機(jī)構(gòu)并且您需要從磁盤手動(dòng)更新證書,那么您應(yīng)該使用 Micronaut 對(duì)應(yīng)用程序事件的支持觸發(fā) RefreshEvent,其中包含定義 HTTPS 配置的密鑰,Micronaut 將從磁盤重新加載證書并應(yīng)用服務(wù)器的新配置。

您還可以使用刷新管理端點(diǎn),但這僅適用于磁盤上證書的物理位置已更改的情況

例如,以下將從磁盤重新加載先前列出的 HTTPS 配置并將其應(yīng)用于新的傳入請(qǐng)求(例如,此代碼可以運(yùn)行輪詢證書以獲取更改的計(jì)劃作業(yè)):

手動(dòng)刷新 HTTPS 配置

import jakarta.inject.Inject;
import io.micronaut.context.event.ApplicationEventPublisher;
import io.micronaut.runtime.context.scope.refresh.RefreshEvent;
import java.util.Collections;
...

@Inject ApplicationEventPublisher<RefreshEvent> eventPublisher;

...

eventPublisher.publishEvent(new RefreshEvent(
    Collections.singletonMap("micronaut.ssl", "*")
));

啟用 HTTP 和 HTTPS

Micronaut 支持綁定 HTTP 和 HTTPS。要啟用雙協(xié)議支持,請(qǐng)修改您的配置。例如:

雙協(xié)議配置示例

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.server.ssl.enabled=true
micronaut.server.ssl.build-self-signed=true
micronaut.server.dual-protocol=true
micronaut:
  server:
    ssl:
      enabled: true
      build-self-signed: true
    dual-protocol : true
[micronaut]
  [micronaut.server]
    [micronaut.server.ssl]
      enabled=true
      build-self-signed=true
    dual-protocol=true
micronaut {
  server {
    ssl {
      enabled = true
      buildSelfSigned = true
    }
    dualProtocol = true
  }
}
{
  micronaut {
    server {
      ssl {
        enabled = true
        build-self-signed = true
      }
      dual-protocol = true
    }
  }
}
{
  "micronaut": {
    "server": {
      "ssl": {
        "enabled": true,
        "build-self-signed": true
      },
      "dual-protocol": true
    }
  }
}
  • 您必須配置 SSL 才能使 HTTPS 工作。在此示例中,我們僅使用帶有構(gòu)建自簽名的自簽名證書

  • 雙協(xié)議啟用 HTTP 和 HTTPS 是一個(gè)可選功能 - 設(shè)置 dualProtocol 標(biāo)志啟用它。默認(rèn)情況下,Micronaut 只啟用一個(gè)

也可以自動(dòng)將所有 HTTP 請(qǐng)求重定向到 HTTPS。除了前面的配置外,您還需要啟用此選項(xiàng)。例如:

啟用 HTTP 到 HTTPS 重定向

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.server.ssl.enabled=true
micronaut.server.ssl.build-self-signed=true
micronaut.server.dual-protocol=true
micronaut.server.http-to-https-redirect=true
micronaut:
  server:
    ssl:
      enabled: true
      build-self-signed: true
    dual-protocol : true
    http-to-https-redirect: true
[micronaut]
  [micronaut.server]
    [micronaut.server.ssl]
      enabled=true
      build-self-signed=true
    dual-protocol=true
    http-to-https-redirect=true
micronaut {
  server {
    ssl {
      enabled = true
      buildSelfSigned = true
    }
    dualProtocol = true
    httpToHttpsRedirect = true
  }
}
{
  micronaut {
    server {
      ssl {
        enabled = true
        build-self-signed = true
      }
      dual-protocol = true
      http-to-https-redirect = true
    }
  }
}
{
  "micronaut": {
    "server": {
      "ssl": {
        "enabled": true,
        "build-self-signed": true
      },
      "dual-protocol": true,
      "http-to-https-redirect": true
    }
  }
}
  • http-to-https-redirect 啟用 HTTP 到 HTTPS 重定向

Enabling Access Logger

本著 apache mod_log_config 和 Tomcat 訪問日志閥的精神,可以為 HTTP 服務(wù)器啟用訪問記錄器(這適用于 HTTP/1 和 HTTP/2)。

要啟用和配置訪問記錄器,請(qǐng)?jiān)谀呐渲梦募ɡ?nbsp;application.yml)中設(shè)置:

Enabling the access logger

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.server.netty.access-logger.enabled=true
micronaut.server.netty.access-logger.logger-name=my-access-logger
micronaut.server.netty.access-logger.log-format=common
micronaut:
  server:
    netty:
      access-logger:
        enabled: true
        logger-name: my-access-logger
        log-format: common
[micronaut]
  [micronaut.server]
    [micronaut.server.netty]
      [micronaut.server.netty.access-logger]
        enabled=true
        logger-name="my-access-logger"
        log-format="common"
micronaut {
  server {
    netty {
      accessLogger {
        enabled = true
        loggerName = "my-access-logger"
        logFormat = "common"
      }
    }
  }
}
{
  micronaut {
    server {
      netty {
        access-logger {
          enabled = true
          logger-name = "my-access-logger"
          log-format = "common"
        }
      }
    }
  }
}
{
  "micronaut": {
    "server": {
      "netty": {
        "access-logger": {
          "enabled": true,
          "logger-name": "my-access-logger",
          "log-format": "common"
        }
      }
    }
  }
}
  • enabled 啟用訪問記錄器

  • 可選地指定一個(gè)記錄器名稱,默認(rèn)為 HTTP_ACCESS_LOGGER

  • 可選地指定日志格式,默認(rèn)為通用日志格式

過(guò)濾訪問日志

如果你不想記錄對(duì)某些路徑的訪問,你可以在配置中指定正則表達(dá)式過(guò)濾器:

過(guò)濾訪問日志

 Properties Yaml  Toml  Groovy  Hocon  JSON 
micronaut.server.netty.access-logger.enabled=true
micronaut.server.netty.access-logger.logger-name=my-access-logger
micronaut.server.netty.access-logger.log-format=common
micronaut.server.netty.access-logger.exclusions[0]=/health
micronaut.server.netty.access-logger.exclusions[1]=/path/.+
micronaut:
  server:
    netty:
      access-logger:
        enabled: true
        logger-name: my-access-logger
        log-format: common
        exclusions:
          - /health
          - /path/.+
[micronaut]
  [micronaut.server]
    [micronaut.server.netty]
      [micronaut.server.netty.access-logger]
        enabled=true
        logger-name="my-access-logger"
        log-format="common"
        exclusions=[
          "/health",
          "/path/.+"
        ]
micronaut {
  server {
    netty {
      accessLogger {
        enabled = true
        loggerName = "my-access-logger"
        logFormat = "common"
        exclusions = ["/health", "/path/.+"]
      }
    }
  }
}
{
  micronaut {
    server {
      netty {
        access-logger {
          enabled = true
          logger-name = "my-access-logger"
          log-format = "common"
          exclusions = ["/health", "/path/.+"]
        }
      }
    }
  }
}
{
  "micronaut": {
    "server": {
      "netty": {
        "access-logger": {
          "enabled": true,
          "logger-name": "my-access-logger",
          "log-format": "common",
          "exclusions": ["/health", "/path/.+"]
        }
      }
    }
  }
}
  • enabled 啟用訪問記錄器

  • 可選地指定一個(gè)記錄器名稱,默認(rèn)為 HTTP_ACCESS_LOGGER

  • 可選地指定日志格式,默認(rèn)為通用日志格式

登錄配置

除了啟用訪問記錄器之外,您還必須為指定的或默認(rèn)的記錄器名稱添加一個(gè)記錄器。例如,使用默認(rèn)記錄器名稱進(jìn)行 logback:

登錄配置

<appender
    name="httpAccessLogAppender"
    class="ch.qos.logback.core.rolling.RollingFileAppender">
    <append>true</append>
    <file>log/http-access.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <!-- daily rollover -->
        <fileNamePattern>log/http-access-%d{yyyy-MM-dd}.log
        </fileNamePattern>
        <maxHistory>7</maxHistory>
    </rollingPolicy>
    <encoder>
        <charset>UTF-8</charset>
        <pattern>%msg%n</pattern>
    </encoder>
    <immediateFlush>true</immediateFlush>
</appender>

<logger name="HTTP_ACCESS_LOGGER" additivity="false" level="info">
    <appender-ref ref="httpAccessLogAppender" />
</logger>

該模式應(yīng)該只有消息標(biāo)記,因?yàn)槠渌貙⒂稍L問記錄器處理。

日志格式

語(yǔ)法基于 Apache httpd 日志格式。

這些是支持的標(biāo)記:

  • %a - 遠(yuǎn)程IP地址

  • %A - 本地IP地址

  • %b - 發(fā)送的字節(jié)數(shù),不包括 HTTP 標(biāo)頭,如果未發(fā)送任何字節(jié),則為“-”

  • %B - 發(fā)送的字節(jié)數(shù),不包括 HTTP 標(biāo)頭

  • %h - 遠(yuǎn)程主機(jī)名

  • %H - 請(qǐng)求協(xié)議

  • %{<header>}i - 請(qǐng)求標(biāo)頭。如果參數(shù)被省略 (%i) 所有的標(biāo)題都被打印出來(lái)

  • %{<header>}o - 響應(yīng)頭。如果省略參數(shù) (%o),則打印所有標(biāo)題

  • %{<cookie>}C - 請(qǐng)求 cookie (COOKIE)。如果省略參數(shù) (%C),則打印所有 cookie

  • %{<cookie>}c - 響應(yīng) cookie (SET_COOKIE)。如果省略參數(shù) (%c),則打印所有 cookie

  • %l - 來(lái)自 identd 的遠(yuǎn)程邏輯用戶名(始終返回“-”)

  • %m - 請(qǐng)求方法

  • %p - 本地端口

  • %q - 查詢字符串(不包括“?”字符)

  • %r - 請(qǐng)求的第一行

  • %s - 響應(yīng)的 HTTP 狀態(tài)代碼

  • %{<format>}t - 日期和時(shí)間。如果省略參數(shù),則使用通用日志格式 ("'['dd/MMM/yyyy:HH:mm:ss Z']'")。

    • 如果格式以 begin 開頭:(默認(rèn))時(shí)間是在請(qǐng)求處理開始時(shí)采用的。如果它以end開頭:它是日志條目被寫入的時(shí)間,接近請(qǐng)求處理的結(jié)束。

    • 格式應(yīng)遵循 DateTimeFormatter 語(yǔ)法。

  • %{property}u - 遠(yuǎn)程認(rèn)證用戶。當(dāng) micronaut-session 在類路徑上時(shí),如果參數(shù)被省略則返回會(huì)話 ID,否則指定的屬性會(huì)打印“-”

  • %U - 請(qǐng)求的 URI

  • %v - 本地服務(wù)器名稱

  • %D - 處理請(qǐng)求所花費(fèi)的時(shí)間,以毫秒為單位

  • %T - 處理請(qǐng)求所花費(fèi)的時(shí)間,以秒為單位

此外,您可以為常見模式使用以下別名:

  • common - %h %l %u %t "%r" %s %b 通用日志格式 (CLF)
  • combined - %h %l %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" 組合日志格式

啟動(dòng)二級(jí)服務(wù)器

Micronaut支持通過(guò)NettyEmbeddedServerFactory接口以編程方式創(chuàng)建額外的Netty服務(wù)器。

這在你需要通過(guò)不同的端口和潛在的不同配置(HTTPS,線程資源等)暴露不同的服務(wù)器的情況下非常有用。

下面的例子演示了如何定義一個(gè)Factory Bean,使用程序化創(chuàng)建的配置啟動(dòng)一個(gè)額外的服務(wù)器。

以編程方式創(chuàng)建二級(jí)服務(wù)器

 Java Groovy  Kotlin 
import java.util.Collections;
import io.micronaut.context.annotation.Bean;
import io.micronaut.context.annotation.Context;
import io.micronaut.context.annotation.Factory;
import io.micronaut.context.annotation.Requires;
import io.micronaut.context.env.Environment;
import io.micronaut.core.util.StringUtils;
import io.micronaut.discovery.ServiceInstanceList;
import io.micronaut.discovery.StaticServiceInstanceList;
import io.micronaut.http.server.netty.NettyEmbeddedServer;
import io.micronaut.http.server.netty.NettyEmbeddedServerFactory;
import io.micronaut.http.server.netty.configuration.NettyHttpServerConfiguration;
import io.micronaut.http.ssl.ServerSslConfiguration;
import jakarta.inject.Named;

@Factory
public class SecondaryNettyServer {
    public static final String SERVER_ID = "another"; // (1)

    @Named(SERVER_ID)
    @Context
    @Bean(preDestroy = "close") // (2)
    @Requires(beans = Environment.class)
    NettyEmbeddedServer nettyEmbeddedServer(NettyEmbeddedServerFactory serverFactory) { // (3)
        // configure server programmatically
        final NettyHttpServerConfiguration configuration =
                new NettyHttpServerConfiguration(); // (4)
        final ServerSslConfiguration sslConfiguration = new ServerSslConfiguration(); // (5)
        sslConfiguration.setBuildSelfSigned(true);
        sslConfiguration.setEnabled(true);
        sslConfiguration.setPort(-1); // random port
        final NettyEmbeddedServer embeddedServer = serverFactory.build(configuration, sslConfiguration); // (6)
        embeddedServer.start(); // (7)
        return embeddedServer; // (8)
    }

    @Bean
    ServiceInstanceList serviceInstanceList( // (9)
            @Named(SERVER_ID) NettyEmbeddedServer nettyEmbeddedServer) {
        return new StaticServiceInstanceList(
                SERVER_ID,
                Collections.singleton(nettyEmbeddedServer.getURI())
        );
    }
}
import io.micronaut.context.annotation.Bean
import io.micronaut.context.annotation.Context
import io.micronaut.context.annotation.Factory
import io.micronaut.context.annotation.Requires
import io.micronaut.context.env.Environment
import io.micronaut.core.util.StringUtils
import io.micronaut.discovery.ServiceInstanceList
import io.micronaut.discovery.StaticServiceInstanceList
import io.micronaut.http.server.netty.NettyEmbeddedServer
import io.micronaut.http.server.netty.NettyEmbeddedServerFactory
import io.micronaut.http.server.netty.configuration.NettyHttpServerConfiguration
import io.micronaut.http.ssl.ServerSslConfiguration
import jakarta.inject.Named

@Factory
class SecondaryNettyServer {
    static final String SERVER_ID = "another" // (1)

    @Named(SERVER_ID)
    @Context
    @Bean(preDestroy = "stop") // (2)
    @Requires(beans = Environment.class)
    NettyEmbeddedServer nettyEmbeddedServer(NettyEmbeddedServerFactory serverFactory) { // (3)
        def configuration =
                new NettyHttpServerConfiguration() // (4)
        def sslConfiguration = new ServerSslConfiguration() // (5)
        sslConfiguration.setBuildSelfSigned(true)
        sslConfiguration.enabled = true
        sslConfiguration.port = -1 // random port
        // configure server programmatically
        final NettyEmbeddedServer embeddedServer = serverFactory.build(configuration, sslConfiguration) // (5)
        embeddedServer.start() // (6)
        return embeddedServer // (7)
    }

    @Bean
    ServiceInstanceList serviceInstanceList( // (8)
                                             @Named(SERVER_ID) NettyEmbeddedServer nettyEmbeddedServer) {
        return new StaticServiceInstanceList(
                SERVER_ID,
                [ nettyEmbeddedServer.URI ]
        )
    }
}
import io.micronaut.context.annotation.Bean
import io.micronaut.context.annotation.Context
import io.micronaut.context.annotation.Factory
import io.micronaut.context.annotation.Requires
import io.micronaut.context.env.Environment
import io.micronaut.core.util.StringUtils
import io.micronaut.discovery.ServiceInstanceList
import io.micronaut.discovery.StaticServiceInstanceList
import io.micronaut.http.server.netty.NettyEmbeddedServer
import io.micronaut.http.server.netty.NettyEmbeddedServerFactory
import io.micronaut.http.server.netty.configuration.NettyHttpServerConfiguration
import io.micronaut.http.ssl.ServerSslConfiguration
import jakarta.inject.Named

@Factory
class SecondaryNettyServer {
    companion object {
        const val SERVER_ID = "another" // (1)
    }

    @Named(SERVER_ID)
    @Context
    @Bean(preDestroy = "close") // (2)
    @Requires(beans = [Environment::class])
    fun nettyEmbeddedServer(
        serverFactory: NettyEmbeddedServerFactory // (3)
    ) : NettyEmbeddedServer {
        val configuration = NettyHttpServerConfiguration() // (4)
        val sslConfiguration = ServerSslConfiguration() // (5)

        sslConfiguration.setBuildSelfSigned(true)
        sslConfiguration.isEnabled = true
        sslConfiguration.port = -1 // random port

        // configure server programmatically
        val embeddedServer = serverFactory.build(configuration, sslConfiguration) // (6)
        embeddedServer.start() // (7)
        return embeddedServer // (8)
    }

    @Bean
    fun serviceInstanceList( // (9)
        @Named(SERVER_ID) nettyEmbeddedServer: NettyEmbeddedServer
    ): ServiceInstanceList {
        return StaticServiceInstanceList(
            SERVER_ID, setOf(nettyEmbeddedServer.uri)
        )
    }
}
  1. 為服務(wù)器定義一個(gè)唯一的名稱
  2. 使用服務(wù)器名稱定義一個(gè) @Context 范圍的 bean,并包括 preDestroy="close" 以確保在上下文關(guān)閉時(shí)關(guān)閉服務(wù)器

  3. 將 NettyEmbeddedServerFactory 注入工廠 Bean

  4. 以編程方式創(chuàng)建 NettyHttpServerConfiguration

  5. 可選擇創(chuàng)建 ServerSslConfiguration

  6. 使用build方法構(gòu)建服務(wù)器實(shí)例

  7. 使用start方法啟動(dòng)服務(wù)器

  8. 將服務(wù)器實(shí)例作為托管 bean 返回

  9. 如果您希望通過(guò)服務(wù)器名稱注入 HTTP 客戶端,可選擇定義 ServiceInstanceList 的實(shí)例

有了這個(gè)類,當(dāng) ApplicationContext 啟動(dòng)時(shí),服務(wù)器也將以適當(dāng)?shù)呐渲脝?dòng)。

由于在步驟 8 中定義了 ServiceInstanceList,您可以將客戶端注入到測(cè)試中以測(cè)試輔助服務(wù)器:

注入服務(wù)器或客戶端

 Java Groovy  Kotlin 
@Client(path = "/", id = SecondaryNettyServer.SERVER_ID)
@Inject
HttpClient httpClient; // (1)

@Named(SecondaryNettyServer.SERVER_ID)
EmbeddedServer embeddedServer; // (2)
@Client(path = "/", id = SecondaryNettyServer.SERVER_ID)
@Inject
HttpClient httpClient // (1)

@Named(SecondaryNettyServer.SERVER_ID)
EmbeddedServer embeddedServer // (2)
@Inject
@field:Client(path = "/", id = SecondaryNettyServer.SERVER_ID)
lateinit var httpClient : HttpClient // (1)

@Inject
@field:Named(SecondaryNettyServer.SERVER_ID)
lateinit var embeddedServer : EmbeddedServer // (2)
  1. 使用服務(wù)器名稱通過(guò) ID 注入客戶端

  2. 使用@Named 注釋作為限定符來(lái)注入嵌入式服務(wù)器實(shí)例


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)