1. Q.启动报错:INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
A.开启apr协议:参考 配置Tomcat apr运行模式 - 星朝 - 博客园
大概过程:
安装对应的apr库;
bin/catalina.sh文件引入apr:
JAVA_OPTS="$JAVA_OPTS -Djava.library.path=/usr/local/apr/lib"
server.xml:
<!-- 默认开启apr监听,注释掉,启动tomcat时就不去找apr库了 -->
<!--APR library loader. Documentation at /docs/apr.html -->
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
......
<Connector port="9082" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="9443" URIEncoding="UTF-8" />
<Connector port="9182" protocol="org.apache.coyote.http11.Http11NioProtocol"
connectionTimeout="20000"
redirectPort="9443" URIEncoding="UTF-8" />
<Connector port="9082" protocol="org.apache.coyote.http11.Http11AprProtocol"
connectionTimeout="20000"
redirectPort="9443" URIEncoding="UTF-8" />
注意:
tomcat性能:apr >= nio > bio ,apr和nio性能差不多,不必强行使用apr。
tomcat8及高版本 默认使用nio,tomcat7 默认使用bio。
2. Q.server.xml里<Server port="9006" shutdown="SHUTDOWNxx"> 什么意思:
telnet localhost 9006,输入SHUTDOWNxx,就可以关闭tomcat.
注意:9006监听在127.0.0.1,所以只能 telnet localhost ,除非自己做端口转发。
注意:如果去掉port参数,则默认使用8005端口。
3.Q. 设置JAVA_OPTS:
catalina.sh:
JAVA_OPTS="$JAVA_OPTS -server -Xms1024m -Xmx3000m -XX:PermSize=256M -XX:MaxNewSize=256m -XX:MaxPermSize=256m -Djava.awt.headless
=true -Dfile.encoding='UTF-8'"
4.Q. 登陆manager:
tomcat-users.xml:
<role rolename="manager-gui"/>
<user username="tomcat" password="mypassword" roles="manager-gui"/>
5.Q. 多个tomcat7 (tomcat8以上暂时没有合适的库)使用redis做session共享,可免去在nginx做会话保持:
tomcat7/lib下放置库:commons-logging-1.2.jar commons-pool2-2.4.2.jar jedis-2.8.2.jar tomcat-juli.jar tomcat-redis-session-manage-tomcat7.jar
context.xml 增加:
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
host="127.0.0.1"
port="6379"
password="redispassword"
database="0"
maxInactiveInterval="60"/>
6.Q. /ROOT/index.jsp 自动跳转:
<%@ page language="java" pageEncoding="UTF-8" %>
<script type="text/javascript">
window.location = "/sso/logon/password.jsp";
</script>
7.Q. AJP端口(反向代理长连接专用端口)可以关闭,除非有反向代理连接这个端口。
server.xml
<!-- Define an AJP 1.3 Connector on port 8009 -->
<!--
<Connector port="9009" protocol="AJP/1.3" redirectPort="8443" />
-->
8.Q. 多个tomcat负载均衡调试jsp页面: 可以显示服务器IP,只修改header.jsp内容做区分即可。
index.jsp:
<%@ page language="java" pageEncoding="UTF-8" %>
<%@ page import="java.util.*" %>
<%@ page import="java.net.InetAddress" %>
<%
InetAddress address = InetAddress.getLocalHost();
String ip=address .getHostAddress().toString();
pageContext.setAttribute("ip",ip);
%>
<script type="text/javascript">
//window.location = "/sso/logon/password.jsp";
</script>
<body>
<jsp:include page="header.jsp"/>
<a href="login.jsp">login</a><br>
<a href="logout.jsp">logout</a><br>
<br>
<%
String user = "";
//if (!StringUtils.isBlank(request.getSession().getAttribute("USER"))) {
if (null != request.getSession().getAttribute("USER")) {
user = request.getSession().getAttribute("USER").toString().trim();
}
//User user = (User) request.getSession().getAttribute("USER");
if ("".equalsIgnoreCase(user)) {
//out.println("用户为空,没有登录!!!");
%>
用户为空,没有登录!!!
<%
} else {
%>
欢迎: <%=user%>
<%
}
%>
login.jsp:
<%@ page language="java" pageEncoding="UTF-8" %>
<body>
<jsp:include page="header.jsp"/>
<form action="/do_login.jsp?type=login" method="post">
用户名:<input type="text" name="username" value="li_si" /><br/>
密码:<input type="password" name="password" value="lisi_password" /><br/>
<input type="submit" value="login">
</form>
</body>
do_login.jsp:
<%@ page language="java" pageEncoding="UTF-8" %>
<%@ page import="org.apache.commons.lang.StringUtils" %>
<%
String username = "";
String password = "";
if (!StringUtils.isBlank(request.getParameter("username"))) {
username = request.getParameter("username");
}
if (!StringUtils.isBlank(request.getParameter("password"))) {
password = request.getParameter("password");
}
request.getSession().setAttribute("USER", username + password);
out.println("User = " + username + " || " + password);
//Thread.sleep(3000);
response.sendRedirect("index.jsp");
%>
logout.jsp:
<%@ page language="java" pageEncoding="UTF-8" %>
<%@ page import="org.apache.commons.lang.StringUtils" %>
<%
request.getSession().setAttribute("USER", "");
out.println("User logout! ");
//Thread.sleep(3000);
response.sendRedirect("index.jsp");
%>
header.jsp: 不同的tomcat,修改Tomcat2为其他的,做区分。
<%@ page language="java" pageEncoding="UTF-8" %>
<%@ page import="java.util.*" %>
<%@ page import="java.net.InetAddress" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + reque
st.getServerPort() + path + "/";
InetAddress address = InetAddress.getLocalHost();
String ip=address .getHostAddress().toString();
pageContext.setAttribute("ip",ip);
%>
<h2>Session Demo in <font color="red"> Tomcat1 <%=ip%></font></h2>
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + reque
st.getServerPort() + path + "/";
<br><%=basePath%>
<br><br>
9.Q. nginx + tomcat 负载均衡(https):
/etc/nginx/conf.d/backend.conf:
#http + https loadbalance
upstream sso_backend {
least_conn;
#ip_hash;
# null= round robin
zone tcp_servers 64k;
server 127.0.0.1:9181;
#server 127.0.0.1:9182;
#server 127.0.0.1:9183;
}
# https://www.ktanx.com/blog/p/5009
server {
listen 9080;
# SSL config
listen 9443 ssl;
#keepalive_timeout 70;
ssl_certificate server_chain.crt;
ssl_certificate_key server.pkcs8;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_verify_depth 2;
status_zone tcp_server;
proxy_redirect http:// $scheme://;
port_in_redirect on;
location / {
#proxy_set_header Host $host:$server_port;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://sso_backend;
}
}
tomcat server.xml: 这里的48190和48144是最终用户在浏览器里打的url 里的端口。
......
<Valve className="org.apache.catalina.valves.AccessLogValve" directory
="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
<!--
http://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/valves/RemoteI
pValve.html
-->
<Valve className="org.apache.catalina.valves.RemoteIpValve"
remoteIpHeader="X-Forwarded-For"
protocolHeader="X-Forwarded-Proto"
protocolHeaderHttpsValue="https"
httpServerPort="48190"
httpsServerPort="48144"
/>
</Host>
</Engine>
</Service>
</Server>
10.
启动时有提示:org.apache.jasper.servlet.TldScanner.scanJars 至少有一个JAR被扫描
catalina.properties
jarsToSkip=\ 改成 jarsToSkip=*.jar
============================================
# - Test JARs (JUnit, Cobertura and dependencies)
#tomcat.util.scan.StandardJarScanFilter.jarsToSkip=\
tomcat.util.scan.StandardJarScanFilter.jarsToSkip=*.jar
annotations-api.jar,\
ant-junit*.jar,\
ant-launcher.jar,\
11. localhost_access_*.txt 写入延迟:
server.xml 增加:buffered="false"
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
resolveHosts="false"
buffered="false"
pattern="%h %l %u %t "%r" [%{postdata}r] %s %{Referer}i %{User
-Agent}i %T %b %D" />
12. tomcat只监听IPV4地址:
server.xml增加
address="0.0.0.0"
<Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol"
address="0.0.0.0"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
keystoreFile="conf/192.168.103.150.jks" keystorePass="jkspassword"
clientAuth="false" sslProtocol="TLS"/>
补: 20201012,上面的方法在centos73下无效,原因未知。
建议使用如下方法:
catalina.sh 里增加 -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv4Addresses 有效。
如:
JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms1024m -Xmx2048m -XX:NewSize=512m -XX:MaxNewSize=1024m -XX:PermSize=512m -XX:MaxP
ermSize=512m -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv4Addresses"
补:服务器完全禁用IPV6方法:
/etc/sysctl.conf
增加:
# 禁止ipv6
net.ipv6.conf.all.disable_ipv6 =1
net.ipv6.conf.default.disable_ipv6 =1
sysctl -p 立即生效,或者重启生效。
13.记录post参数(2021-02-02):
https://www.cnblogs.com/yinliang/p/7495342.html
================================================
tomcat/conf/server.xml:
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs_ex"
buffered="false"
prefix="post_log" suffix=".txt"
pattern="%h %l %u %t "%r" [%{postdata}r] %s %T %b" />
=================================================
tomcat/webapps/uts/WEB-INF/web.xml:
<filter>
<filter-name>post-data-dumper-filter</filter-name>
<filter-class>com.terry.PostDataDumperFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>post-data-dumper-filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
=================================================
com.zip解压到tomcat/webapps/app/WEB-INF/classes/
unipz com.zip -d ./com/
=================================================
查看日志方法:
tail -f logs_ex/post_log.txt
PostDataDumperFilter代码:
package com.terry;
/**
* Created by Terry2 on 2021/2/2.
* https://www.cnblogs.com/yinliang/p/7495342.html
*/
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class PostDataDumperFilter implements Filter {
Logger logger = LoggerFactory.getLogger(getClass());
private FilterConfig filterConfig = null;
public void destroy() {
this.filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (filterConfig == null)
return;
Enumeration<String> names = request.getParameterNames();
StringBuilder output = new StringBuilder();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
output.append(name).append("=");
String values[] = request.getParameterValues(name);
for (int i = 0; i < values.length; i++) {
if (i > 0) {
output.append("' ");
}
output.append(values[i]);
}
if (names.hasMoreElements())
output.append("&");
}
request.setAttribute("postdata", output);
//request.setAttribute("log_postdata_only", null);
logger.debug("postdata: " + output);
chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
}
14.Q. xx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx