背景:完成完整的業(yè)務(wù),需要第三方異步回調(diào)系統(tǒng)的接口。從而更新業(yè)務(wù)狀態(tài)。但是第三方系統(tǒng)經(jīng)常只能配置一個(gè)回調(diào)接口。但是我們系統(tǒng)有4個(gè)環(huán)境。常常只能在一個(gè)環(huán)境測(cè)試,切換環(huán)境測(cè)試需要去第三方修改回調(diào)接口。
目標(biāo):接口回調(diào)回來后,允許接口轉(zhuǎn)發(fā)到其他環(huán)境
實(shí)現(xiàn)思路:由于回調(diào)接口中是沒有參數(shù)能標(biāo)識(shí)發(fā)到哪個(gè)環(huán)境,因此無法在nginx層面解決。就在具體服務(wù)上做:
接收請(qǐng)求,找到需要轉(zhuǎn)發(fā)到哪些環(huán)境
封裝請(qǐng)求,將回調(diào)請(qǐng)求轉(zhuǎn)發(fā)過去(header帶上標(biāo)識(shí):x-forward-from)
如果請(qǐng)求帶有x-forward-from,則不轉(zhuǎn)發(fā)
同時(shí)本服務(wù)也接收該請(qǐng)求并處理
這些邏輯都是和接口邏輯不相干的,因此考慮切面等方式處理,最后采用filter處理。邏輯在filter中處理
以下是遇到的相關(guān)問題:項(xiàng)目采取SpringMVC
Q:WebApplicationContext獲取HttpClient的bean失敗
call其他環(huán)境用封裝的HttpClient的bean,它是一個(gè)帶線程池的,filter通過在web.xml進(jìn)行配置生效。如下:
NotifyMessageForwardFilter com.lenovo.ofp.payment.front.webapp.filter.NotifyMessageForwardFilter NotifyMessageForwardFilter /notify/*
這種方式,可以看作是new NotifyMessageForwardFilter()。無法通過@Auwired 注入bean,會(huì)報(bào)錯(cuò)。當(dāng)然這個(gè)報(bào)錯(cuò)具體原因是因?yàn)閒ilter調(diào)用時(shí),bean對(duì)象還沒初始化好:web.xml中各個(gè)標(biāo)簽初始化的順序如下:contetxt-param ->listener ->filter ->servlet
用來加載你配置的文件信息配置你的監(jiān)聽服務(wù)過濾器配置你單獨(dú)的一些操作容器初始化
加載順序?yàn)椋篶ontext-param ->listener ->filter ->servlet 加載的順序不受在web.xml中配置的位置影響
springmvc.xml中定義component-scan;而springmvc.xml在servlet中加載;所以filter中找不到servlet才生成的bean
其次是WebApplicationContext獲取的applicationContext,它id是:org.springframework.web.context.WebApplicationContext:/payment-front-webapp,通過BeanDefinitionNames()這個(gè)方法發(fā)現(xiàn),沒有HttpClient的bean,連Controller的bean都沒有。因此才認(rèn)為,至少還有一個(gè)其他的ApplicationContext
而servlet的applicationContext的id是:org.springframework.web.context.WebApplicationContext:/payment-front-webapp/dispatcher
發(fā)現(xiàn)了吧,ApplicationContext不是一個(gè),所以呀,我們要用下面那個(gè)。
A:解決方法:通過上面的分析,我們也知道ApplicationContext除了WebApplicationUtils獲取的那個(gè)外,還存在至少一個(gè)。所以用ApplicationContextAware來獲取。畢竟這個(gè)接口是在服務(wù)啟動(dòng)完成后執(zhí)行的內(nèi)容。獲取的Context更為完整。
@Component
public class ApplicationContextUtils implements ApplicationContextAware {
public static ApplicationContext APPLICATION_CONTEXT = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
log.info("init ApplicationContextUtils success");
ApplicationContextUtils.APPLICATION_CONTEXT = applicationContext;
}
}
Q1:org.apache.http.ProtocolException: Content-Length header already present
A:content-length是根據(jù)內(nèi)容的長(zhǎng)度動(dòng)態(tài)計(jì)算的。因此在請(qǐng)求轉(zhuǎn)發(fā)的時(shí)候,要?jiǎng)h掉
Q2:requestBody無法被重復(fù)讀取
請(qǐng)求轉(zhuǎn)發(fā)到不同環(huán)境,這意味著我們需要封裝http請(qǐng)求,需要讀取body。而body讀取一次后就會(huì)報(bào)錯(cuò)。
A:body無法被重復(fù)讀取原因是body內(nèi)容放在InputStream中,這個(gè)流是只能讀一次的,根據(jù)HttpServletRequestWrapper包裝一下就行了
public class HttpMultiReadServletRequestWrapper extends HttpServletRequestWrapper {
BufferedReader bufferedReader = null;
String requestBody = "";
public HttpMultiReadServletRequestWrapper(HttpServletRequest request) {
super(request);
// 用原始的request獲取一次body,然后緩存起來
this.requestBody = HttpRequestUtils.getRequestBody(request);
}
@Override
public ServletInputStream getInputStream() throws IOException {
String characterEncoding = getCharacterEncoding();
characterEncoding = StringUtils.isBlank(characterEncoding) ? "UTF-8" : characterEncoding;
return new DelegatingServletInputStream(
new ByteArrayInputStream(requestBody.getBytes(characterEncoding)));
}
@Override
public BufferedReader getReader() throws IOException {
if (bufferedReader == null) {
// 需要搭配StringReader才能反復(fù)讀。用inputStream只能讀一次
bufferedReader = new BufferedReader(new StringReader(requestBody));
bufferedReader.mark(requestBody.length() + 1);
} else {
// 重置之后,bufferedReader就又可以讀了
bufferedReader.reset();
}
return bufferedReader;
}
public String getRequestBody() {
return this.requestBody;
}
}
HttpRequestUtils的getRequestBody內(nèi)容如下
public static String getRequestBody(HttpServletRequest request) {
StringBuilder sb = new StringBuilder();
try {
BufferedReader br = request.getReader();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
} catch (Exception e) {
log.error("Read notify request body", e);
}
return sb.toString();
}
Q3:@Autowired request是代理類,無法加載為了解決requestBody而生成RequestWrapper
A:其實(shí)就是一個(gè)實(shí)現(xiàn)邏輯出錯(cuò)。我們生成RequestWrapper后,應(yīng)當(dāng)在filterChain里面?zhèn)魅隦equestWrapper而不是原來的request。其次是:RequestContextHolder,這個(gè)是在filter之前就設(shè)置了Request,所以有必要,需要更新里面的Request
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
網(wǎng)頁標(biāo)題:第三方接口回調(diào)轉(zhuǎn)發(fā)到不同環(huán)境-創(chuàng)新互聯(lián)
網(wǎng)頁路徑:http://jinyejixie.com/article12/depsdc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站排名、電子商務(wù)、虛擬主機(jī)、域名注冊(cè)、關(guān)鍵詞優(yōu)化、外貿(mào)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容