這裡分類和彙總了欣宸的全部原創(含配套原始碼):https://github.com/zq2599/blog_demos
接下來開發一個header filter試試,還記得《Java擴充套件Nginx之一:你好,nginx-clojure》一文中的/java介面嗎,那是個最簡單的helloworld級別的location,content handler是HelloHandler.java,稍後驗證header filter功能的時候會用到它
先用postman請求/java介面,看看沒有使用header filter之前的response header,如下圖:
接下來新增一個location,設定如下,content handler還是HelloHandler.java,增加了header_filter_type和header_filter_name:
location /headerfilterdemo {
content_handler_type 'java';
content_handler_name 'com.bolingcavalry.simplehello.HelloHandler';
# header filter的型別是java
header_filter_type 'java';
# header
header_filter_name 'com.bolingcavalry.filterdemo.RemoveAndAddMoreHeaders';
}
package com.bolingcavalry.filterdemo;
import nginx.clojure.java.Constants;
import nginx.clojure.java.NginxJavaHeaderFilter;
import java.util.Map;
public class RemoveAndAddMoreHeaders implements NginxJavaHeaderFilter {
@Override
public Object[] doFilter(int status, Map<String, Object> request, Map<String, Object> responseHeaders) {
// 先刪再加,相當於修改了Content-Type的值
responseHeaders.remove("Content-Type");
responseHeaders.put("Content-Type", "text/html");
// 增加兩個header
responseHeaders.put("Xfeep-Header", "Hello2!");
responseHeaders.put("Server", "My-Test-Server");
// 返回PHASE_DONE表示告知nginx-clojure框架,當前filter正常,可以繼續執行其他的filter和handler
return Constants.PHASE_DONE;
}
}
# body filter的demo,response body是字串型別
location /stringbodyfilterdemo {
content_handler_type 'java';
content_handler_name 'com.bolingcavalry.simplehello.HelloHandler';
# body filter的型別是java
body_filter_type 'java';
# body filter的類
body_filter_name 'com.bolingcavalry.filterdemo.StringFacedUppercaseBodyFilter';
}
package com.bolingcavalry.filterdemo;
import nginx.clojure.java.StringFacedJavaBodyFilter;
import java.io.IOException;
import java.util.Map;
public class StringFacedUppercaseBodyFilter extends StringFacedJavaBodyFilter {
@Override
protected Object[] doFilter(Map<String, Object> request, String body, boolean isLast) throws IOException {
if (isLast) {
// isLast等於true,表示當前web請求過程中最後一次呼叫doFilter方法,
// body是完整response body的最後一部分,
// 此時返回的status應該不為空,這樣nginx-clojure框架就會完成body filter的執行流程,將status和聚合後的body返回給使用者端
return new Object[] {200, null, body.toUpperCase()};
}else {
// isLast等於false,表示當前web請求過程中,doFilter方法還會被繼續呼叫,當前呼叫只是多次中的一次而已,
// body是完整response body的其中一部分,
// 此時返回的status應該為空,這樣nginx-clojure框架就繼續body filter的執行流程,繼續呼叫doFilter
return new Object[] {null, null, body.toUpperCase()};
}
}
}
File, viz. java.io.File
String
InputStream
Array/Iterable, e.g. Array/List/Set of above types
接下來進入實戰了,詳細步驟如下圖:
首先是開發一個返回二進位制流的web介面,為了簡單省事兒,直接用nginx-clojure的另一個能力來實現:clojure型別的服務,在nginx.conf中新增以下內容即可,程式碼雖然不是java但也能勉強看懂(能看懂就行,畢竟不是重點),就是持續寫入1024行字串,每行的內容都是'123456789':
location /largebody {
content_handler_type 'clojure';
content_handler_code '
(do
(use \'[nginx.clojure.core])
(fn[req]
{:status 200
:headers {}
:body (for [i (range 1024)] "123456789\n")})
)';
}
package com.bolingcavalry.filterdemo;
import nginx.clojure.NginxChainWrappedInputStream;
import nginx.clojure.NginxClojureRT;
import nginx.clojure.java.NginxJavaBodyFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
public class StreamFacedBodyFilter implements NginxJavaBodyFilter {
@Override
public Object[] doFilter(Map<String, Object> request, InputStream bodyChunk, boolean isLast) throws IOException {
// 這裡僅將二進位制檔案長度列印到紀錄檔,您可以按照業務實際情況自行修改
NginxClojureRT.log.info("isLast [%s], total [%s]", String.valueOf(isLast), String.valueOf(bodyChunk.available()));
// NginxChainWrappedInputStream的成員變數index記錄的讀取的位置,本次用完後要重置位置,因為doFilter之外的程式碼中可能也會讀取bodyChunk
((NginxChainWrappedInputStream)bodyChunk).rewind();
if (isLast) {
// isLast等於true,表示當前web請求過程中最後一次呼叫doFilter方法,
// body是完整response body的最後一部分,
// 此時返回的status應該不為空,這樣nginx-clojure框架就會完成body filter的執行流程,將status和聚合後的body返回給使用者端
return new Object[] {200, null, bodyChunk};
}else {
// isLast等於false,表示當前web請求過程中,doFilter方法還會被繼續呼叫,當前呼叫只是多次中的一次而已,
// body是完整response body的其中一部分,
// 此時返回的status應該為空,這樣nginx-clojure框架就繼續body filter的執行流程,繼續呼叫doFilter
return new Object[] {null, null, bodyChunk};
}
}
}
location /streambodyfilterdemo {
# body filter的型別是java
body_filter_type java;
body_filter_name 'com.bolingcavalry.filterdemo.StreamFacedBodyFilter';
proxy_http_version 1.1;
proxy_buffering off;
proxy_pass http://localhost:8080/largebody;
}
2022-02-15 21:34:38[info][23765][main]isLast [false], total [3929]
2022-02-15 21:34:38[info][23765][main]isLast [false], total [4096]
2022-02-15 21:34:38[info][23765][main]isLast [false], total [2215]
2022-02-15 21:34:38[info][23765][main]isLast [true], total [0]
名稱 | 連結 | 備註 |
---|---|---|
專案主頁 | https://github.com/zq2599/blog_demos | 該專案在GitHub上的主頁 |
git倉庫地址(https) | https://github.com/zq2599/blog_demos.git | 該專案原始碼的倉庫地址,https協定 |
git倉庫地址(ssh) | [email protected]:zq2599/blog_demos.git | 該專案原始碼的倉庫地址,ssh協定 |
這個git專案中有多個資料夾,本篇的原始碼在nginx-clojure-tutorials資料夾下的filter-demo子工程中,如下圖紅框所示:
本篇涉及到nginx.conf的修改,完整的參考在此:https://raw.githubusercontent.com/zq2599/blog_demos/master/nginx-clojure-tutorials/files/nginx.conf