2020年10月11日 星期日

[Java] Invalid HTTP method: PATCH

最近系統需要使用 Netty4,所以把衝突的 Netty3 拆掉,然後就出現了例外。

pom.xml

<dependency>
   <groupId>com.ning</groupId>
   <artifactId>async-http-client</artifactId>
   <version>1.9.40</version>
   <exclusions>
      <exclusion>
         <groupId>io.netty</groupId>
         <artifactId>netty</artifactId>
      </exclusion>
   </exclusions>
</dependency>

client

Request request = new RequestBuilder("POST")
      .setUrl(url)
      .setBody(body)
      .setHeader("Content-Type", contentType)
      .setRequestTimeout(timeout)
      .build();
Future&lg4;Response> future = client.executeRequest(request);

console log

[AsyncHttpClient-Callback] DEBUG c.n.h.c.p.jdk.JDKAsyncHttpProvider - Invalid HTTP method: PATCH
java.net.ProtocolException: Invalid HTTP method: PATCH
        at java.net.HttpURLConnection.setRequestMethod(HttpURLConnection.java:440)
        at sun.net.www.protocol.http.HttpURLConnection.setRequestMethod(HttpURLConnection.java:553)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.setRequestMethod(HttpsURLConnectionImpl.java:388)
        at com.ning.http.client.providers.jdk.JDKAsyncHttpProvider$AsyncHttpUrlConnection.configure(JDKAsyncHttpProvider.java:530)
        at com.ning.http.client.providers.jdk.JDKAsyncHttpProvider$AsyncHttpUrlConnection.call(JDKAsyncHttpProvider.java:227)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

可以看到 com.ning:async-http-client 原本是走 Netty3,拿掉之後改走 HttpURLConnection 才是出現例外的主因。 找到的解法有幾個:

  • 使用 head X-HTTP-Method-Override:測試不可行。
  • 複寫 HttpURLConnection.methods:測試不可行,payload 帶不過去。
  • 尋找已解決的 JDK (待確認)
  • 改用新版 org.asynchttpclient:async-http-client;因為底層用的是 Netty4。
  • 改用其他 http client。

雖然 Jersey 也會發生相同問題,但是修改之後可以正常使用。

webTarget.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true);
Response response = webTarget.path(url)
      .request(MediaType.APPLICATION_JSON)
      .method("PATCH", Entity.json(payload.toString()));

參考資料:

2020年9月30日 星期三

[Java] hot reload Yaml

高可用條件之一是能夠 hot reload (熱重載)。簡單的做法是每次使用的時候就是讀檔,使用 Properties 或是 snakeyaml。另一種方法是使用 commons-configuration2 套件提供的功能:

public static ReloadingFileBasedConfigurationBuilder<YAMLConfiguration> getBuilder(File file) {
   Parameters params = new Parameters();
   ReloadingFileBasedConfigurationBuilder<YAMLConfiguration> builder =
      new ReloadingFileBasedConfigurationBuilder<>(YAMLConfiguration.class)
         .configure(params.fileBased().setFile(file));

   // 每次讀取時檢查
   builder.addEventListener(ConfigurationBuilderEvent.CONFIGURATION_REQUEST,
      event -> builder.getReloadingController().checkForReloading(null));

   // 每分鐘檢查
   PeriodicReloadingTrigger trigger = new PeriodicReloadingTrigger(builder.getReloadingController(),
      null, 1, TimeUnit.MINUTES);
   trigger.start();

   return builder;
}

@Test
public void testHotReload() throws Exception {
   File tmpFile = File.createTempFile("test", ".yml");
   tmpFile.deleteOnExit();

   String raw1 = "sample:\n    property: test-1\n";
   Files.write(tmpFile.toPath(), raw1.getBytes());

   ImmutableConfiguration config1 = getBuilder(tmpFile).getConfiguration();
   Assert.assertEquals("test before hot reload", "test-1", config1.getString("sample.property"));

   // NOTE. File#setLastModified() only guarantees that the file modification time is accurate to the second, so
   // the modification must be delayed by 1 second.
   Thread.sleep(1000);
   String raw2 = "sample:\n    property: test-2\n";
   Files.write(tmpFile.toPath(), raw2.getBytes());

   ImmutableConfiguration config2 = getBuilder(tmpFile).getConfiguration();
   Assert.assertEquals("test after hot reload", "test-2", config2.getString("sample.property"));
}

參考資料:

2020年2月13日 星期四

[PHP] 網頁顯示 UTF-8 轉 BIG5

UTF-8 有很多字元是 BIG5 無法支援,但是有時候又需要使用 BIG5,就需要特別轉成 HTML Entities。

mb_substitute_character('entity');
echo mb_convert_encoding('許功蓋開飛機♥⬅️', 'BIG5', 'UTF-8');
// 許功蓋開飛機♥⬅️

[Java] Invalid HTTP method: PATCH

最近系統需要使用 Netty4,所以把衝突的 Netty3 拆掉,然後就出現了例外。 pom.xml <dependency> <groupId>com.ning</groupId> <artifactId>as...