要:此次定位,頗為復雜,而且有時讓人沒有思路,因為同一個接口,換一個環境又好使了,又不敢去懷疑代碼;然而有問題的環境,換一個接口也好使了,又不得不懷疑代碼
本文分享自華為云社區《一次網絡請求超時分析-云社區-華為云》,作者:xiewenci 。
發起http請求,后端服務接口/v5/iot/11c9c88e6fb26bead43b75514dc380eb/routing-rule/rules?limit=10&marker=ffffffffff&offset=0,一直等待,一分鐘后返回響應,且中文亂碼顯示
異常環境的流信息
正常環境的流信息
從圖中看出正常環境是,服務端發送響應完成之后,由客戶端正常返回ACK,然后由客戶端發起FIN斷鏈請求。而異常環境則是服務端發送響應完成之后,客戶端也回了ACK,但是沒有主動發起斷鏈請求,直到超過keep-alive時間之后,由服務端發起了斷鏈請求(因為超時主動斷鏈)。現象是客戶端一直在等服務端發送響應(可能沒有發送完),所以懷疑服務端有緩存之類,沒有及時將響應流發送出去,所以繼續查看代碼
3. 查看代碼,在返回客戶端的時候,沒有flush和close操作,代碼如下
然后以為找到問題原因所在了,就嘗試修改代碼,如下:
增加了flush操作和close操作(放在了try語快中),最后測試執行,還是跟最初的現象一致,還是會等待1分鐘后才會返回響應。這時就有點納悶了,再重新仔細分析,其實從流中可以看出來,服務端的響應是立馬返回給了客戶端的,如下圖
既然給了響應,那為什么客戶端為什么還要繼續等待呢?這里有注意到圖中有幾個問號,這其實是中文字符亂碼了,所以這里又懷疑是不是編碼格式導致客戶端收到的Content-Length長度和收到的響應的長度不一致,也就是客戶端實際收到的響應的長度小于Content-Length的長度,然后一直等待下去,所以繼續修改代碼代碼
4. 修改代碼,指定編碼格式為UTF-8,代碼如下:
替換環境版本,測試執行,響應就立馬返回了,果然是這個編碼格式的鍋
1. 編碼格式不一致就會導致響應流的實際長度不一致?答案是一定的,編碼格式不一致,實際長度就是會不一致,測試結果如下:
2. 為什么之前的沒有出現過這個問題?是什么原因導致編碼格式丟失的
查看后端服務jar包,發現spring版本已經升級到5.2.21.RELEASE,此版本中沒有指定默認編碼格式為UTF-8
所以需要后端服務去指定編碼格式,或者網關服務統一處理
此次定位,頗為復雜,而且有時讓人沒有思路,因為同一個接口,換一個環境又好使了,又不敢去懷疑代碼;然而有問題的環境,換一個接口也好使了,又不得不懷疑代碼;還有就是在容器中去調用接口,也是一樣的問題,所以感覺又跟網絡沒啥關系。其實應該靜下心來去思考為什么客戶端那里一直等待,沒有主動發起斷鏈,這里還是說明了對HTTP協議細節,不夠熟練掌握,才導致中間走了一些誤區,需要去鞏固和加深對http協議的理解。
點擊下方,第一時間了解華為云新鮮技術~
華為云博客_大數據博客_AI博客_云計算博客_開發者中心-華為云
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>3.0.9.RELEASE</version>
</dependency>
<!-- 使用thymeleaf解析 -->
<bean id="templateResolver"
class="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".html" />
<property name="templateMode" value="HTML" />
<property name="cacheable" value="false" />
<property name="characterEncoding" value="UTF-8"/><!--不加會亂碼-->
</bean>
<bean id="templateEngine"
class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver" />
</bean>
<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
<!--解決中文亂碼-->
<property name="characterEncoding" value="UTF-8"/>
</bean>
<!-- 配置視圖解析器 -->
<!--<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">-->
<!--<property name="prefix" value="/WEB-INF/" />-->
<!--<property name="suffix" value=".jsp" />-->
<!--</bean>-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-ioc.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--SpringMVC配置文件的名字 <servlet-name>-servlet.xml
默認位置:src / resources
如果放在了 src/resources(maven)
contextConfigLocation:classpath:文件名即可!
Web-INF/xx.xml
contextConfigLocation:/WEB-INF/xx.xml
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 訪問DispatcherServlet對應的路徑 -->
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern> <!--/不過濾jsp防止死循環-->
</servlet-mapping>
<!--配置thymeleaf -->
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
package com.test.action;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("thymeleaf")
public class ThymeleafAction {
@RequestMapping("/testThymeleaf")
public String testThymeleaf(Model model)
{
model.addAttribute("uname","zhangsan");
return "testThymeleaf";// WEB-INF/views/testThymeleaf.html
}
}
根據之前設置的前綴
在web-inf/views/文件夾下創建html文件
訪問傳遞過來的數據,注意聲明Thymeleaf命名空間
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text="${uname}">aaaa</h1>
</body>
</html>
? http://localhost:8080/testssm/thymeleaf/testThymeleaf
? 成功
?
html有的屬性,Thymeleaf基本都有,而常用的屬性大概有七八個。其中th屬性執行的優先級從1~8,數字越低優先級越高。
一、th:text :設置當前元素的文本內容,相同功能的還有th:utext,兩者的區別在于前者不會轉義html標簽,后者會。優先級不高:order=7
二、th:value:設置當前元素的value值,類似修改指定屬性的還有th:src,th:href。優先級不高:order=6
三、th:each:遍歷循環元素,和th:text或th:value一起使用。注意該屬性修飾的標簽位置,詳細往后看。優先級很高:order=2
四、th:if:條件判斷,類似的還有th:unless,th:switch,th:case。優先級較高:order=3
五、th:insert:代碼塊引入,類似的還有th:replace,th:include,三者的區別較大,若使用不恰當會破壞html結構,常用于公共代碼塊提取的場景。優先級最高:order=1
六、th:fragment:定義代碼塊,方便被th:insert引用。優先級最低:order=8
七、th:object:聲明變量,一般和*{}一起配合使用,達到偷懶的效果。優先級一般:order=4
八、th:attr:修改任意屬性,實際開發中用得較少,因為有豐富的其他th屬性幫忙,類似的還有th:attrappend,th:attrprepend。優先級一般:order=5
由上文也可以知道需要在html中添加:
<html xmlns:th="http://www.thymeleaf.org">
這樣,下文才能正確使用th:*形式的標簽!
通過**${…}進行取值,這點和ONGL表達式語法一致!**
<h1 th:text="${uname}"></h1>
<input type="text" th:value="${uname}" />
選擇變量表達式*{…}
<div th:object="${items}">
<p th:text="*{name}" >產品名</p>
<p th:text="*{detail}" >產品名</p>
</div>
至于p里面的原有的值只是為了給前端開發時做展示用的.這樣的話很好地做到了前后端分離。
這也是Thymeleaf非常好的一個特性:在無網絡的情況下也能運行,也就是完全可以前端先寫出頁面,模擬數據展現效果,后端人員再拿此模板修改即可!
用來配合link src href使用的語法,類似的標簽有:th:href和th:src
無參:@{/xxx}
有參:@{/xxx(k1=v1,k2=v2)} 對應url結構:xxx?k1=v1&k2=v2
引入本地資源:@{/項目本地的資源路徑}
引入外部資源:@{/webjars/資源在jar包中的路徑}
列舉:第三部分的實戰引用會詳細使用該表達式
<link th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" rel="stylesheet">
<link th:href="@{/main/css/itdragon.css}" rel="stylesheet">
<form class="form-login" th:action="@{/user/login}" th:method="post" >
<a class="btn btn-sm" th:href="@{/login.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/login.html(l='en_US')}">English</a>
<a href="details.html" th:href="@{/thymeleaf/showItemsById(id=${items.id})}">view</a>
變量表達式有豐富的內置方法,使其更強大,更方便。
一、可以獲取對象的屬性和方法
二、可以使用ctx,vars,locale,request,response,session,servletContext內置對象
三、可以使用dates,numbers,strings,objects,arrays,lists,sets,maps等內置方法(重點介紹)
一、ctx :上下文對象。
二、vars :上下文變量。
三、locale:上下文的語言環境。
四、request:(僅在web上下文)的 HttpServletRequest 對象。
五、response:(僅在web上下文)的 HttpServletResponse 對象。
六、session:(僅在web上下文)的 HttpSession 對象。
七、servletContext:(僅在web上下文)的 ServletContext 對象
這里以常用的Session舉例,用戶刊登成功后,會把用戶信息放在Session中,Thymeleaf通過內置對象將值從session中獲取。
// java 代碼將用戶名放在session中
session.setAttribute("userinfo",username);
// Thymeleaf通過內置對象直接獲取
th:text="${session.userinfo}"
一、strings:字符串格式化方法,常用的Java方法它都有。比如:equals,equalsIgnoreCase,length,trim,toUpperCase,toLowerCase,indexOf,substring,replace,startsWith,endsWith,contains,containsIgnoreCase等
二、numbers:數值格式化方法,常用的方法有:formatDecimal等
三、bools:布爾方法,常用的方法有:isTrue,isFalse等
四、arrays:數組方法,常用的方法有:toArray,length,isEmpty,contains,containsAll等
五、lists,sets:集合方法,常用的方法有:toList,size,isEmpty,contains,containsAll,sort等
六、maps:對象方法,常用的方法有:size,isEmpty,containsKey,containsValue等
七、dates:日期方法,常用的方法有:format,year,month,hour,createNow等
文章底部提供了對應的官網鏈接
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>ITDragon Thymeleaf 內置方法</title>
</head>
<body>
<h2>ITDragon Thymeleaf 內置方法</h2>
<h3>#strings </h3>
<div th:if="${not #strings.isEmpty(itdragonStr)}" >
<p>Old Str : <span th:text="${itdragonStr}"/></p>
<p>toUpperCase : <span th:text="${#strings.toUpperCase(itdragonStr)}"/></p>
<p>toLowerCase : <span th:text="${#strings.toLowerCase(itdragonStr)}"/></p>
<p>equals : <span th:text="${#strings.equals(itdragonStr, 'itdragonblog')}"/></p>
<p>equalsIgnoreCase : <span th:text="${#strings.equalsIgnoreCase(itdragonStr, 'itdragonblog')}"/></p>
<p>indexOf : <span th:text="${#strings.indexOf(itdragonStr, 'r')}"/></p>
<p>substring : <span th:text="${#strings.substring(itdragonStr, 2, 8)}"/></p>
<p>replace : <span th:text="${#strings.replace(itdragonStr, 'it', 'IT')}"/></p>
<p>startsWith : <span th:text="${#strings.startsWith(itdragonStr, 'it')}"/></p>
<p>contains : <span th:text="${#strings.contains(itdragonStr, 'IT')}"/></p>
</div>
<h3>#numbers </h3>
<div>
<p>formatDecimal 整數部分隨意,小數點后保留兩位,四舍五入: <span th:text="${#numbers.formatDecimal(itdragonNum, 0, 2)}"/></p>
<p>formatDecimal 整數部分保留五位數,小數點后保留兩位,四舍五入: <span th:text="${#numbers.formatDecimal(itdragonNum, 5, 2)}"/></p>
</div>
<h3>#bools </h3>
<div th:if="${#bools.isTrue(itdragonBool)}">
<p th:text="${itdragonBool}"></p>
</div>
<h3>#arrays </h3>
<div th:if="${not #arrays.isEmpty(itdragonArray)}">
<p>length : <span th:text="${#arrays.length(itdragonArray)}"/></p>
<p>contains : <span th:text="${#arrays.contains(itdragonArray, 5)}"/></p>
<p>containsAll : <span th:text="${#arrays.containsAll(itdragonArray, itdragonArray)}"/></p>
</div>
<h3>#lists </h3>
<div th:if="${not #lists.isEmpty(itdragonList)}">
<p>size : <span th:text="${#lists.size(itdragonList)}"/></p>
<p>contains : <span th:text="${#lists.contains(itdragonList, 0)}"/></p>
<p>sort : <span th:text="${#lists.sort(itdragonList)}"/></p>
</div>
<h3>#maps </h3>
<div th:if="${not #maps.isEmpty(itdragonMap)}">
<p>size : <span th:text="${#maps.size(itdragonMap)}"/></p>
<p>containsKey : <span th:text="${#maps.containsKey(itdragonMap, 'thName')}"/></p>
<p>containsValue : <span th:text="${#maps.containsValue(itdragonMap, '#maps')}"/></p>
</div>
<h3>#dates </h3>
<div>
<p>format : <span th:text="${#dates.format(itdragonDate)}"/></p>
<p>custom format : <span th:text="${#dates.format(itdragonDate, 'yyyy-MM-dd HH:mm:ss')}"/></p>
<p>day : <span th:text="${#dates.day(itdragonDate)}"/></p>
<p>month : <span th:text="${#dates.month(itdragonDate)}"/></p>
<p>monthName : <span th:text="${#dates.monthName(itdragonDate)}"/></p>
<p>year : <span th:text="${#dates.year(itdragonDate)}"/></p>
<p>dayOfWeekName : <span th:text="${#dates.dayOfWeekName(itdragonDate)}"/></p>
<p>hour : <span th:text="${#dates.hour(itdragonDate)}"/></p>
<p>minute : <span th:text="${#dates.minute(itdragonDate)}"/></p>
<p>second : <span th:text="${#dates.second(itdragonDate)}"/></p>
<p>createNow : <span th:text="${#dates.createNow()}"/></p>
</div>
</body>
</html>
后臺給負責給變量賦值,和跳轉頁面。
@RequestMapping("varexpressions")
public String varexpressions(ModelMap map) {
map.put("itdragonStr", "itdragonBlog");
map.put("itdragonBool", true);
map.put("itdragonArray", new Integer[]{1,2,3,4});
map.put("itdragonList", Arrays.asList(1,3,2,4,0));
Map itdragonMap = new HashMap();
itdragonMap.put("thName", "${#...}");
itdragonMap.put("desc", "變量表達式內置方法");
map.put("itdragonMap", itdragonMap);
map.put("itdragonDate", new Date());
map.put("itdragonNum", 888.888D);
return "grammar/varexpressions";
}
?
數學運算
邏輯運算
比較運算(為避免轉義尷尬,可以使用括號中的英文進行比較運算!)
條件運算
if/unless
使用th:if和th:unless屬性進行條件判斷,th:unless于th:if恰好相反,只有表達式中的條件不成立,才會顯示其內容。
<td ><span th:if="${items.price gt 1000}" >精品</span></td>
<td ><span th:unless="${items.price gt 1000}" >次品</span></td>
switch
<div th:switch="${items.name}">
<p th:case="'aa'">aaaaaaaaa</p>
<p th:case="'bb'">bbbbbbb</p>
<p th:case="'cc'">cccccccc</p>
</div>
th:each
thymeleaf的th:each常見用法
一.th:eath迭代集合用法:
<table border="1" id="stuTable">
<tr>
<td>是否選中</td>
<td>編號</td>
<td>姓名</td>
<td>年齡</td>
</tr>
<tr th:each="stu,userStat:${studentList}" >
<td><input th:type="checkbox" th:name="id" th:value="${stu.id}"></td>
<td th:text="${stu.id}">編號</td>
<td th:text="${stu.name}">姓名</td>
<td th:text="${stu.age}">年齡</td>
</tr>
</table>
二.迭代下標變量用法:
狀態變量定義在一個th:每個屬性和包含以下數據:
1.當前迭代索引,從0開始。這是索引屬性。index
2.當前迭代索引,從1開始。這是統計屬性。count
3.元素的總量迭代變量。這是大小屬性。 size
4.iter變量為每個迭代。這是目前的財產。 current
5.是否當前迭代是奇數還是偶數。這些even/odd的布爾屬性。
6.是否第一個當前迭代。這是first布爾屬性。
7.是否最后一個當前迭代。這是last布爾屬性。
用法實例:
<table border="1" id="stuTable">
<tr>
<td>是否選中</td>
<td>編號</td>
<td>姓名</td>
<td>年齡</td>
</tr>
<tr th:each="stu,userStat:${studentList}" th:class="${userStat.odd}?'odd':'even'">
<td th:text="${userStat.index}"></td>
<td><input th:type="checkbox" th:name="id" th:value="${stu.id}"></td>
<td th:text="${stu.id}">編號</td>
<td th:text="${stu.name}">姓名</td>
<td th:text="${stu.age}">年齡</td>
</tr>
</table>
package com.test.action;
import com.test.pojo.Items;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Controller
@RequestMapping("thymeleaf")
public class ThymeleafAction {
@RequestMapping("/testThymeleaf")
public String testThymeleaf(Model model)
{
model.addAttribute("uname","zhangsan");
Items items=new Items();
items.setId(1);
items.setName("iphone");
items.setDetail("9999");
items.setPrice(6000);
model.addAttribute("items",items);
List<Items> itemsList=new ArrayList<Items>();
itemsList.add(new Items(101,"aa",1000,"aaa","1.jpg",new Date()));
itemsList.add(new Items(102,"bb",1000,"aaa","1.jpg",new Date()));
itemsList.add(new Items(103,"cc",1000,"aaa","1.jpg",new Date()));
model.addAttribute("itemsList",itemsList);
return "testThymeleaf";
}
@RequestMapping("/showItemsById")
public String showItemsById(Model model,int id)
{
model.addAttribute("id",id);
return "showItemsById";
}
}
tems);
List<Items> itemsList=new ArrayList<Items>();
itemsList.add(new Items(101,"aa",1000,"aaa","1.jpg",new Date()));
itemsList.add(new Items(102,"bb",1000,"aaa","1.jpg",new Date()));
itemsList.add(new Items(103,"cc",1000,"aaa","1.jpg",new Date()));
model.addAttribute("itemsList",itemsList);
return "testThymeleaf";
}
@RequestMapping("/showItemsById")
public String showItemsById(Model model,int id)
{
model.addAttribute("id",id);
return "showItemsById";
}
}
大廠是大部分程序員的夢想,而進大廠的門檻也是比較高的,所以這里整理了一份阿里、美團、滴滴、頭條等大廠面試大全其中概括的知識點有:Java基礎、spring、springmvc、springboot、springcloud、JVM、Tomcat、dubbo、netty、zookeeper共有500+道面試題
面試題整理十分全面,文末還有答案解析!(文章比較長,耐心看完,讓你面試提升一大截!)
獲取以下面試專題答案的朋友們請轉發此文關注我私信回復“面試資料”即可獲取
Java基礎124道面試答案
JVM 40道面試答案
Spring 80道面試題答案
SpringMVC 30道面試答案
SpringBoot 40道面試答案
SpringCloud 34道面試答案
Mybatis 面試答案
Redis 70道面試答案解析
Dubbo面試答案
Tomcat面試答案
Zookeeper 面試答案
Netty 面試答案
獲取以上面試專題答案的朋友們請轉發此文關注我私信回復“面試資料”即可獲取
面試答案匯總
Java核心知識283頁覆蓋了JVM、鎖、并發、Java反射、Spring原理、微服務、Zookeeper、數據庫、數據結構等大量知識點
如果需要獲取到這個【核心知識點整理】文檔的話幫忙轉發一下然后再關注我私信回復“面試資料”得到獲取方式吧!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。