浏览 4.2k
1、 nginx增加自定义模块,代码如下nginx-1.12.2\src\http\modules\ngx_http_demo1_module.c
其中 调用rc=ngx_http_read_client_request_body(r, ngx_http_demo1_body_handler); 读取POST内容 。
2、客户端使用 java: connection =(HttpURLConnection) urls.openConnection();的POST请求
** 问题:HttpURLConnection请求一次成功后,该connect无法断开,导致第二次post会超时。
但只要做一次 get的请求 ,再做post就会成功。
发现问题出在 增加了改语句 ngx_http_read_client_request_body(...)就存在这个问题。
对比发现,使用Python POST或苹果手机APP的 POST都没有这个问题。只有 JAVA HttpURLConnection的 POST才存在这个问题。
nginx-1.12.2\src\http\modules\ngx_http_demo1_module.c
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#define NGX_DEMO1_DATA_LEN 2*1024 // 655360 // 640*1024
static char *ngx_http_demo1(ngx_conf_t *cf, ngx_command_t *cmd,void *conf);
static ngx_command_t ngx_http_demo1_commands[] = {
{ ngx_string("DEMO1"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | \
NGX_CONF_NOARGS,
ngx_http_demo1,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
ngx_null_command
};
static ngx_http_module_t ngx_http_demo1_module_ctx = {
NULL, /* preconfiguration */
NULL, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
NULL, /* create location configuration */
NULL /* merge location configuration */
};
ngx_module_t ngx_http_demo1_module = {
NGX_MODULE_V1,
&ngx_http_demo1_module_ctx, /* module context */
ngx_http_demo1_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_int_t ngx_http_demo1_get_handler(ngx_http_request_t *r,char *str) {
ngx_int_t rc=NGX_OK;
rc = ngx_http_discard_request_body(r);
if (rc != NGX_OK) {
return rc;
}
ngx_str_t type = ngx_string("text/plain");
ngx_str_t response =ngx_string(str);// ngx_string("Hello World!");
response.len=strlen(str);
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = response.len;
r->headers_out.content_type = type;
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
ngx_buf_t *b;
b = ngx_create_temp_buf(r->pool, response.len);
if (b == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ngx_memcpy(b->pos, response.data, response.len);
b->last = b->pos + response.len;
b->last_buf = 1;
ngx_chain_t out;
out.buf = b;
out.next = NULL;
return ngx_http_output_filter(r, &out);
}
void ngx_http_demo1_body_handler(ngx_http_request_t *r)
{
ngx_connection_t *c;
c = r->connection;
ngx_log_error(NGX_LOG_ERR, c->log, 0, "ngx_http_demo1_body_handler -->");
}
static ngx_int_t ngx_http_demo1_handler(ngx_http_request_t *r) {
ngx_int_t rc=NGX_OK;
ngx_connection_t *c;
c = r->connection;
ngx_log_error(NGX_LOG_ERR, c->log, 0, "demo POST --> r->method:%d",r->method);
if (!(r->method & (NGX_HTTP_POST))) {
return ngx_http_demo1_get_handler(r,"[GET] hello world!");
}
//POST:
rc=ngx_http_read_client_request_body(r, ngx_http_demo1_body_handler);///// HERE ,ISSUE!!!
rc=ngx_http_demo1_get_handler(r,"[POST] test!");
return rc;
}
static char *
ngx_http_demo1(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *clcf;
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
clcf->handler = ngx_http_demo1_handler;
return NGX_CONF_OK;
}
java代码如下:
NginText1.java
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public class NginxTest1 {
static String HTTP_URL="http://10.162.129.21:8080/demo1";
private static String[] postUrl={
"{\"user\": \"demo1\",\"age\": 1}",
"{\"user\": \"demo1\",\"age\": 2}",
"{\"user\": \"demo1\",\"age\": 3}",
"{\"user\": \"demo1\",\"age\": 4}",
"{\"user\": \"demo1\",\"age\": 5}",
"{\"user\": \"demo1\",\"age\": 6}",
};
public void test(){
new Thread(new Runnable() {
@Override
public void run() {
testThreaqd();
}
}).start();
}
static int postUrlIndex=0;
public void testThreaqd() {
System.out.println("test-->");
for (int i=0;i<postUrl.length;i++){
System.out.println("--->\n");
postURL(HTTP_URL, postUrl[postUrlIndex]);
postUrlIndex++;
}
}
private String postURL(String url,String jsonParam) {
//System.setProperty("sun.net.http.retryPost", "false");
System.out.println(postUrlIndex+ ":"+jsonParam);
String back = "";
HttpURLConnection connection=null;
try {
URL urls = new URL(url);
System.out.println("--1->");
connection =(HttpURLConnection) urls.openConnection();
if (connection==null) {
System.out.println("Error: connect lost!");
}
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("content-Type", "application/json;charset=utf-8");
// 接收的内容类型也是json格式
connection.setRequestProperty("Accept", "application/json;charset=utf-8");
connection.setDoOutput(true);//允许输出流
connection.setConnectTimeout(3000);
connection.setReadTimeout(3000);
OutputStream os = connection.getOutputStream();
os.write(jsonParam.getBytes("utf-8"));//将 JSON 数据写入输出流
os.flush();//确保数据被发送出去
os.close();// 关闭输出流
connection.connect();
int responseCode = connection.getResponseCode();
System.out.println("--2: " +responseCode);
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream inputStream = connection.getInputStream();// 获取输入流来读取响应数据。
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.setLength(0);
String line;
while ((line = reader.readLine()) != null) {
System.out.println("--3:: "+line);
stringBuilder.append(line);
}
reader.close();
inputStream.close();
back = stringBuilder.toString();
}else{
//处理错误响应。
back = "error";
System.out.println("--4:error back");
}
System.out.println("--5->");
}catch(Exception e){
System.out.println(e.toString());
back = e.toString();
}finally{
if (connection != null) {
System.out.println("disconnect()");
//connection.disconnect();
if (false){
try {
System.out.println("--6->");
// 出现一个问题java.net.SocketTimeoutException: Read timed out,
// 这个postURL()函数连续执行,会出现第一次成功,偶数次都会超时的问题。
// 增加这几行代码,刻意解决问题
URL urls = new URL(url);
connection = (HttpURLConnection) urls.openConnection();
connection.setRequestMethod("GET");
connection.setReadTimeout(1);
connection.getResponseCode();
} catch (Exception e) {
}
}
}
}
System.out.println("return :"+back);
return back;
}
}
按点赞数排序
按时间排序
LOG如下:偶数次是超时。
Hello and welcome!
test-->
--->
0:{"user": "demo1","age": 1}
--1->
--2: 200
--3:: [POST] test!
--5->
disconnect()
return :[POST] test!
--->
1:{"user": "demo1","age": 2}
--1->
java.net.SocketTimeoutException: Read timed out
disconnect()
return :java.net.SocketTimeoutException: Read timed out
--->
2:{"user": "demo1","age": 3}
--1->
--2: 200
--3:: [POST] test!
--5->
disconnect()
return :[POST] test!
--->
3:{"user": "demo1","age": 4}
--1->
java.net.SocketTimeoutException: Read timed out
disconnect()
return :java.net.SocketTimeoutException: Read timed out
--->
4:{"user": "demo1","age": 5}
--1->
--2: 200
--3:: [POST] test!
--5->
disconnect()
return :[POST] test!
--->
5:{"user": "demo1","age": 6}
--1->
java.net.SocketTimeoutException: Read timed out
disconnect()
return :java.net.SocketTimeoutException: Read timed out
Process finished with exit code 0
0
回答于2024-11-12 16:15
sticky模块只能在linux下吧,win下没有。tomcat好像有个session复制吧,或者可以用共享session。
没办法完全不受影响的,因为mirror是子请求,当子请求未结束时,主请求消耗的内存至少是无法释放的。你可以尝试在/mirror里,把超时时间大幅度调低,包括connect/read/send,再压下看看。
微信公众号
加入微信群