การแยกวิเคราะห์คำขอ HTTP ด้วยตัวกรองบันทึก Java
javax.servlet.Filterนี่คือเครื่องมือที่สะดวกในการวิเคราะห์เนื้อหาของคำขอ HTTP และแสดงผลเป็นบันทึก (log)กรองขอแนะนำนักเรียนทุกคนครับ/ค่ะ
ตัวกรองบันทึกนี้ใช้ "java.util.logging.Logger" สำหรับการแสดงผลบันทึก และคุณสามารถเปลี่ยนข้อมูลที่แสดงผลได้โดยการเปลี่ยนระดับการบันทึก
javax.servlet.Filter คืออะไร?
ในการสร้างเว็บแอปพลิเคชัน นอกเหนือจากกระบวนการทางธุรกิจหลักแล้ว ยังจำเป็นต้องดำเนินการกระบวนการรองที่มักเกิดขึ้นก่อนและหลังกระบวนการหลักเหล่านั้นด้วย
ตัวอย่างเช่น การตรวจสอบสิทธิ์ไคลเอ็นต์ การตรวจสอบสิทธิ์ การบันทึกข้อมูล เป็นต้น
การเขียนโค้ดกระบวนการรองดังกล่าวลงในแต่ละทรัพยากรเป็นอุปสรรคสำคัญต่อการบำรุงรักษาซอฟต์แวร์ และส่งผลให้แอปพลิเคชันนั้นยากต่อการบำรุงรักษา
ด้วยการใช้งาน javax.servlet.Filter คุณสามารถทำการประมวลผลขั้นที่สองนี้ได้ก่อนที่จะส่งคำขอไปยังคลาสเซิร์ฟเล็ต
นอกจากนี้ เนื่องจากสามารถกำหนดค่าการตั้งค่าตัวกรองได้ในไฟล์ web.xml คุณจึงสามารถเพิ่มหรือลบตัวกรองได้อย่างยืดหยุ่นโดยไม่ต้องแก้ไขซอร์สโค้ด
ลองใช้ตัวกรองบันทึกดูครับ
เรามาลองใช้ตัวกรองบันทึกเพื่อวิเคราะห์คำขอ HTTP โดยการกรองคำขอเหล่านั้นกันดู
ครั้งนี้ทอมแคทเราจะใช้แอปพลิเคชันตัวอย่างที่มาพร้อมกับโปรแกรมโดยค่าเริ่มต้น
สามารถเรียกใช้ตัวกรองนี้ได้ทันทีหลังจากตั้งค่าต่อไปนี้เสร็จสิ้น
2. วางไฟล์คลาสที่คอมไพล์แล้วไว้ในโฟลเดอร์ "/examples/WEB-INF/classes"
3. กำหนดค่าต่อไปนี้ในไฟล์ web.xml
ตัวกรองบันทึก ตัวกรองบันทึก ระดับการบันทึก ดี ตัวกรองบันทึก /*
*รูปแบบ URL เมื่อใช้เฟรมเวิร์ก Struts มีดังนี้:
*.ทำ
โปรดตรวจสอบผลลัพธ์ในบันทึกเมื่อคุณเรียกใช้หน้าจอตัวอย่างเซสชัน

ข้อมูลบันทึกที่จะส่งออกและระดับการบันทึก
●เนื้อหาเอาต์พุตบันทึก
| ข้อมูลบันทึก | ระดับบันทึก |
|---|---|
| ข้อมูลเกี่ยวกับคุกกี้ | ดี |
| ข้อมูลส่วนหัว HTTP | ดี |
| ข้อมูลเกี่ยวกับ HTTP และข้อมูลอื่นๆ | ดี |
| พารามิเตอร์คำขอ HTTP | การกำหนดค่า |
| วัตถุที่มีขอบเขตตามคำขอ | การกำหนดค่า |
| วัตถุที่มีขอบเขตเซสชัน | การกำหนดค่า |
| ปริมาณการใช้หน่วยความจำก่อนและหลังการร้องขอ | การกำหนดค่า |
| ข้อมูลการเปลี่ยนหน้าจอ | ข้อมูล |
คุณควรใช้ระดับการบันทึกข้อมูลต่อไปนี้เพื่อแยกความแตกต่างระหว่างข้อมูลเหล่านั้น
- ละเอียดที่สุด... แสดงบันทึกรายละเอียดสูงสุด ตั้งค่านี้เมื่อคุณต้องการวิเคราะห์คำขอ HTTP อย่างละเอียด
- CONFIG... จะแสดงบันทึกรายละเอียดที่มากกว่าเล็กน้อย ควรตั้งค่าไว้ที่ระดับนี้ในระหว่างการพัฒนา
- ข้อมูล... แสดงเฉพาะข้อมูลการเปลี่ยนหน้าจอเท่านั้น
● วิธีการเปลี่ยนระดับการบันทึกข้อมูล
คุณสามารถเปลี่ยนระดับการแสดงผลบันทึกได้โดยการตั้งค่าพารามิเตอร์เริ่มต้น logging.Level
ตัวอย่าง:
ระดับการบันทึก ข้อมูล
ซอร์สโค้ด
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 javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* พัฒนาคลาส javax.servlet.Filter เพื่อแยกวิเคราะห์เนื้อหาของคำขอ HTTP และแสดงผลบันทึก (log) ออกมา
* คลาสตัวกรอง
*/
คลาสสาธารณะ LogFilter implements Filter {
ส่วนตัวแบบคงที่ Logger logger =
Logger.getLogger(LogFilter.class.getName());
private static final String LINE_SEPA =
System.getProperty(“line.separator”);
private static final String NEXT_PAGE = “LogFilter.NEXT_PAGE”;
/**
* เริ่มต้นใช้งานตัวกรองบันทึกนี้
* @param mapping
*/
public void init(FilterConfig mapping) {
String str = mapping.getInitParameter(“logging.Level”);
System.out.println("กำลังตั้งค่าระดับการบันทึกเป็น "+str+".");
ระดับ = null;
พยายาม {
ระดับ = Level.parse(str);
} catch (Exception e) {
e.printStackTrace();
ระดับ = ระดับ.INFO;
}
LogManager.getLogManager().reset();
Handler handler = new CustomConsoleHandler();
handler.setFormatter(new CustomFormatter());
handler.setLevel(level);
logger.setLevel(level);
logger.getParent().addHandler(ตัวจัดการ);
}
/**
* นี่คือตัวกรองที่แสดงผลบันทึก (log)
* @param request คำขอ HTTP ที่กำลังประมวลผล
* @param response การตอบสนอง HTTP ที่กำลังสร้างขึ้น
* @param chain
*/
public void doFilter(ServletRequest _request, ServletResponse _response,
FilterChain chain) โยน IOException, ServletException {
// —————————————————————『การประมวลผลล่วงหน้า』
HttpServletRequest request = (HttpServletRequest) _request;
HttpServletResponse response = (HttpServletResponse) _response;
ถ้า (logger.isLoggable(Level.CONFIG)) {
logger.Config(
“============ เริ่มการร้องขอ!!”
+"รหัสกระทู้:"”
+ Thread.currentThread().hashCode()
+ ” ========================================================” ลิขสิทธิ์;
}
// การใช้งานหน่วยความจำ
สตริง actionMemory = null;
ถ้า (logger.isLoggable(Level.CONFIG)) {
actionMemory = getMemoryInfo(" "”
+ เวลาใหม่ (System.currentTimeMillis()) + " คำขอ [ก่อนหน้า]");
}
ถ้า (logger.isLoggable(Level.FINE)) {
logger.fine("ข้อมูลคุกกี้" + getCookieInfo(request));
}
ถ้า (logger.isLoggable(Level.FINE)) {
logger.fine("ข้อมูลส่วนหัว HTTP" + getHeadersInfo(request));
}
ถ้า (logger.isLoggable(Level.FINE)) {
เครื่องบันทึก
.fine("ข้อมูลอื่นๆ ของ HTTP" + getRequestOtherInfo(request));
}
ถ้า (logger.isLoggable(Level.CONFIG)) {
String reqlog = getRequestParametersInfo(request);
logger.config("พารามิเตอร์คำขอ HTTP" + reqlog);
}
ถ้า (logger.isLoggable(Level.CONFIG)) {
logger.config("อ็อบเจ็กต์ที่มีขอบเขตตามคำขอ")“
+ รับข้อมูลแอตทริบิวต์คำขอ (คำขอ));
}
ถ้า (logger.isLoggable(Level.CONFIG)) {
String sessionlog = getSessionInfo(request,true);
logger.config("อ็อบเจ็กต์ที่มีขอบเขตเซสชัน (ก่อนการประมวลผลคำขอ)")“
+ บันทึกเซสชัน);
}
// เรียกใช้ฟิลเตอร์ต่อไปนี้
chain.doFilter(request, response);
// ———————————————————-『การประมวลผลภายหลัง』
ถ้า (logger.isLoggable(Level.CONFIG)) {
String sessionlog = getSessionInfo(request,false);
logger.config("อ็อบเจ็กต์ที่มีขอบเขตเซสชัน (หลังจากการประมวลผลคำขอ)")“
+ บันทึกเซสชัน);
}
// การใช้งานหน่วยความจำ
ถ้า (logger.isLoggable(Level.CONFIG)) {
actionMemory = "ปริมาณการใช้หน่วยความจำก่อนและหลังการร้องขอ" + LINE_SEPA
+ actionMemory + LINE_SEPA
+ getMemoryInfo(" " + new Time(System.currentTimeMillis())
+ "ขอ [หลังจากนั้น]");
logger.config(actionMemory+LINE_SEPA);
}
// ข้อมูลเกี่ยวกับการเปลี่ยนฉาก
ถ้า (logger.isLoggable(Level.INFO)) {
String nextPage = (String) request.getAttribute(NEXT_PAGE);
if (nextPage == null || nextPage.length() == 0) {
nextPage = request.getRequestURI();
}
logger.info(“NEXT_PAGE=[” + nextPage + “], ”
+ “IP_ADDRESS=[” + request.getRemoteAddr() + “], ”
+ “SESSION_ID=[” + request.getSession().getId() + “], ”
+ “USER-AGENT=[” + request.getHeader(“user-agent”) + “]”);
}
ถ้า (logger.isLoggable(Level.CONFIG)) {
logger.Config(
“============ สิ้นสุดคำขอ!!”
+”รหัสเธรด:”+ Thread.currentThread().hashCode()
+ ” ========================================================”
+LINE_SEPA+LINE_SEPA);
}
}
/**
*
*/
public void destroy() {
}
// ------- เมธอดส่วนตัวด้านล่าง -------
private static String getMemoryInfo(String message) {
DecimalFormat dFromat = new DecimalFormat(“#,###KB”);
long free = Runtime.getRuntime().freeMemory() / 1024;
รวมยาว = Runtime.getRuntime().totalMemory() / 1024;
ยาวสูงสุด = Runtime.getRuntime().maxMemory() / 1024;
ใช้งานมานาน = ฟรีทั้งหมด;
String msg = message + ": " + "Total=" + dFromat.format(total) + ", "”
+ “การใช้งาน =" + dFromat.format(ที่ใช้) + ” (” + (ที่ใช้ * 100 / ทั้งหมด)
+ “%), จำนวนสูงสุดที่ใช้ได้ =” + dFromat.format(max);
ส่งข้อความกลับ;
}
/**
* บันทึกส่วนหัวของคำขอทั้งหมด
*/
private static String getHeadersInfo(HttpServletRequest request) {
StringBuffer buff = new StringBuffer(LINE_SEPA);
Enumeration headerNames = request.getHeaderNames();
ในขณะที่ (headerNames.hasMoreElements()) {
String headerName = (String) headerNames.nextElement();
บัฟ.อัปเอนด์("");
buff.append(headerName);
บัฟ.อัปเอนด์("=");
buff.append(request.getHeader(headerName));
buff.append(LINE_SEPA);
}
return buff.toString();
}
private static String getCookieInfo(HttpServletRequest request) {
StringBuffer buff = new StringBuffer();
Cookie[] cookies = request.getCookies();
ถ้า (คุกกี้ == null) {
กลับ "";
}
for (int i = 0; i < cookies.length; i++) {
buff.append(“\n — คุกกี้[” + i + “] —\n”);
บัฟ.อัปเอนด์("");
buff.append(cookies[i].getName());
บัฟ.อัปเอนด์("=");
buff.append(cookies[i].getValue());
buff.append(LINE_SEPA);
บัฟ.อัปเอนด์("");
buff.append(“getVersion()”);
บัฟ.อัปเอนด์("=");
buff.append(cookies[i].getVersion());
buff.append(LINE_SEPA);
บัฟ.อัปเอนด์("");
buff.append(“getComment()”);
บัฟ.อัปเอนด์("=");
buff.append(cookies[i].getComment());
buff.append(LINE_SEPA);
บัฟ.อัปเอนด์("");
buff.append(“getDomain()”);
บัฟ.อัปเอนด์("=");
buff.append(cookies[i].getDomain());
buff.append(LINE_SEPA);
บัฟ.อัปเอนด์("");
buff.append(“getMaxAge()”);
บัฟ.อัปเอนด์("=");
buff.append(cookies[i].getMaxAge());
buff.append(LINE_SEPA);
บัฟ.อัปเอนด์("");
buff.append("getPath()");
บัฟ.อัปเอนด์("=");
buff.append(cookies[i].getPath());
buff.append(LINE_SEPA);
บัฟ.อัปเอนด์("");
buff.append(“getSecure()”);
บัฟ.อัปเอนด์("=");
buff.append(cookies[i].getSecure());
buff.append(LINE_SEPA);
}
return buff.toString();
}
private static String getRequestParametersInfo(HttpServletRequest request) {
StringBuffer buff = new StringBuffer(LINE_SEPA);
แผนที่ map = convertRequest(request);
TreeMap trr = new TreeMap(map);
Iterator itr = trr.keySet().iterator();
ในขณะที่ (itr.hasNext()) {
สตริง key = (สตริง) itr.next();
บัฟ.อัปเอนด์("");
บัฟ.อัปเอนด์(คีย์);
บัฟ.อัปเอนด์("=");
ค่าของอ็อบเจ็กต์ = map.get(key);
ค่าของสตริง[] = ค่าของ (สตริง[]);
if (values.length == 1) {
buff.append(values[0]);
อื่น {
// แปลงอาร์เรย์สตริง
String strValue = stratum(values);
buff.append(strValue);
}
buff.append(LINE_SEPA);
}
return buff.toString();
}
private static String getRequestAttributeInfo(HttpServletRequest request) {
StringBuffer buff = new StringBuffer(LINE_SEPA);
การแจงนับ e = request.getAttributeNames();
ในขณะที่ (e.hasMoreElements()) {
ชื่อสตริง = (สตริง) e.nextElement();
buff.append(” name=” + name + “, attributeClass= ”
+ request.getAttribute(name).getClass().getName()
+ “, toString() = ” + request.getAttribute(name)
+ LINE_SEPA);
}
return buff.toString();
}
private static String getRequestOtherInfo(HttpServletRequest request) {
StringBuffer buff = new StringBuffer();
buff.append(LINE_SEPA);
buff.append(”getCharacterEncoding()=”);
buff.append(request.getCharacterEncoding());
buff.append(LINE_SEPA);
buff.append(”getContentLength()=”);
buff.append(request.getContentLength());
buff.append(LINE_SEPA);
buff.append(”getContentType()=”);
buff.append(request.getContentType());
buff.append(LINE_SEPA);
buff.append(”getLocale()=”);
buff.append(request.getLocale());
buff.append(LINE_SEPA);
buff.append(”getProtocol()=”);
buff.append(request.getProtocol());
buff.append(LINE_SEPA);
buff.append(”getRemoteAddr()=”);
buff.append(request.getRemoteAddr());
buff.append(LINE_SEPA);
buff.append(”getRemoteHost()=”);
buff.append(request.getRemoteHost());
buff.append(LINE_SEPA);
buff.append(”getScheme()=”);
buff.append(request.getScheme());
buff.append(LINE_SEPA);
buff.append(”getServerName()=”);
buff.append(request.getServerName());
buff.append(LINE_SEPA);
buff.append(”getServerPort()=”);
buff.append(request.getServerPort());
buff.append(LINE_SEPA);
buff.append(”isSecure()=”);
buff.append(request.isSecure());
buff.append(LINE_SEPA);
buff.append(”getAuthType()=”);
buff.append(request.getAuthType());
buff.append(LINE_SEPA);
buff.append(”getContextPath()=”);
buff.append(request.getContextPath());
buff.append(LINE_SEPA);
buff.append(”getMethod()=”);
buff.append(request.getMethod());
buff.append(LINE_SEPA);
buff.append(”getPathInfo()=”);
buff.append(request.getPathInfo());
buff.append(LINE_SEPA);
buff.append(”getPathTranslated()=”);
buff.append(request.getPathTranslated());
buff.append(LINE_SEPA);
buff.append(”getQueryString()=”);
buff.append(request.getQueryString());
buff.append(LINE_SEPA);
buff.append(”getRemoteUser()=”);
buff.append(request.getRemoteUser());
buff.append(LINE_SEPA);
buff.append(”getRequestedSessionId()=”);
buff.append(request.getRequestedSessionId());
buff.append(LINE_SEPA);
buff.append(”getRequestURI()=”);
buff.append(request.getRequestURI());
buff.append(LINE_SEPA);
buff.append(”getServletPath()=”);
buff.append(request.getServletPath());
buff.append(LINE_SEPA);
buff.append(”getUserPrincipal()=”);
buff.append(request.getUserPrincipal());
buff.append(LINE_SEPA);
buff.append(”isRequestedSessionIdFromCookie()=”);
buff.append(request.isRequestedSessionIdFromCookie());
buff.append(LINE_SEPA);
buff.append(”isRequestedSessionIdFromURL()=”);
buff.append(request.isRequestedSessionIdFromURL());
buff.append(LINE_SEPA);
buff.append("isRequestedSessionIdValid()=");
buff.append(request.isRequestedSessionIdValid());
buff.append(LINE_SEPA);
return buff.toString();
}
private static String getSessionInfo(HttpServletRequest request,boolean before) {
HttpSession session = request.getSession();
StringBuffer buff = new StringBuffer();
buff.append(LINE_SEPA);
ถ้า (ก่อน) {
buff.append(” session.isNew() = ” + session.isNew());
buff.append(LINE_SEPA);
buff.append(” session.getId() = ” + session.getId());
buff.append(LINE_SEPA);
}
การแจงนับ e = session.getAttributeNames();
ในขณะที่ (e.hasMoreElements()) {
String sessionName = (String) e.nextElement();
String sessionClassName = session.getAttribute(sessionName)
.getClass().getName();
buff.append(" name =" + sessionName + ", value ="”
+ session.getAttribute(sessionName) + “, attributeClass = ”
+ sessionClassName+LINE_SEPA);
}
return buff.toString();
}
private static Hashtable convertRequest(HttpServletRequest request) {
Hashtable tempHash = new Hashtable();
การแจงนับ e = request.getParameterNames();
ในขณะที่ (e.hasMoreElements()) {
สตริง key = (สตริง) e.nextElement();
ค่าสตริง[] = request.getParameterValues(key);
String[] parameterValues = new String[values.length];
for (int i = 0; i < values.length; i++) {
parameterValues[i] = convUnicode(values[i]);
}
tempHash.put(key, parameterValues);
}
ส่งคืนค่าแฮชชั่วคราว;
}
private static String stratum(Object value) {
ถ้า (ค่า == null) {
ส่งคืนค่า "null"
} else if (value instanceof String[]) {
คืนค่า convString((String[]) value);
อื่น {
return value.toString();
}
}
/**
* ส่งคืนเนื้อหาของอาร์เรย์สตริง [strArray] ในรูปแบบสตริง ดังที่แสดงด้านล่าง
* “[temp1,temp2,temp3]”
* @param strArray อาร์เรย์สตริงที่จะถูกประเมิน
* @return สตริงที่แปลงแล้ว
*/
private static String convString(String[] strArray) {
ถ้า (strArray == null)
ส่งคืนค่าว่าง;
StringBuffer buff = new StringBuffer(“[“);
for (int i = 0; i < strArray.length; i++) {
buff.append(strArray[i] + ", ");
}
buff.delete(buff.length() – 2, buff.length());
บัฟ.อัปเอนด์("]");
return buff.toString();
}
/**
* แปลง [str] เป็น Unicode
* @param str
* @กลับ
*/
private static String convUnicode(String str) {
ถ้า (str == null)
ส่งคืนค่าว่าง;
พยายาม {
ส่งคืนค่าสตริงใหม่ (str.getBytes(“8859_1”), “JISAutoDetect”);
} catch (UnsupportedEncodingException e) {
โยน RuntimeException ใหม่(e);
}
}
// ———————————————————————–
static class CustomFormatter extends Formatter {
static final String pattern = “yyyy/MM/dd HH:mm:ss”;
สาธารณะ synchronized String format(LogRecord record) {
StringBuffer buf = new StringBuffer();
// ตั้งค่าวันที่และเวลา
Date date = new Date();
date.setTime(record.getMillis());
SimpleDateFormat formatter = new SimpleDateFormat(pattern);
buf.append(formatter.format(date));
buf.append(":");
// ตั้งค่าระดับ
buf.append(“[” + record.getLevel().getName() + “]”);
buf.append(":");
buf.append(record.getMessage());
buf.append(LINE_SEPA);
return buf.toString();
}
}
static class CustomConsoleHandler extends StreamHandler {
public CustomConsoleHandler() {
ซูเปอร์();
setOutputStream(System.out);
}
/**
* จะมีการออกบันทึก LogRecord ให้
* ในสถานะเริ่มต้น คำขอการบันทึกจะถูกส่งไปยังอ็อบเจ็กต์ Logger
* ขั้นตอนนี้ดำเนินการเพื่อตอบสนอง และวัตถุนี้จะเริ่มต้น LogRecord
* ข้อความนี้ถูกส่งต่อมาที่นี่
*
* @param record คำอธิบายของเหตุการณ์ในบันทึก หากเป็นค่าว่าง ระบบจะละเว้นข้อมูลนี้
* จะไม่มีการส่งการแจ้งเตือนใดๆ
*/
public void publish(LogRecord record) {
super.publish(record);
ฟลัช();
}
/**
* แม้ว่าคุณจะเขียนทับ StreamHandler.close เพื่อทำการ flush ก็ตาม
* สตรีมเอาต์พุตจะไม่ถูกปิด กล่าวอีกนัยหนึ่งคือ System.err จะไม่ถูกปิด
*/
public void close() {
ฟลัช();
}
}
}
