这里分类和汇总了欣宸的全部原创(含配套源码):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) | git@github.com: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