第三方接口回調(diào)轉(zhuǎn)發(fā)到不同環(huán)境-創(chuàng)新互聯(lián)

背景:完成完整的業(yè)務(wù),需要第三方異步回調(diào)系統(tǒng)的接口。從而更新業(yè)務(wù)狀態(tài)。但是第三方系統(tǒng)經(jīng)常只能配置一個回調(diào)接口。但是我們系統(tǒng)有4個環(huán)境。常常只能在一個環(huán)境測試,切換環(huán)境測試需要去第三方修改回調(diào)接口。

網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)!專注于網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、成都微信小程序、集團企業(yè)網(wǎng)站建設(shè)等服務(wù)項目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了西夏免費建站歡迎大家使用!

目標:接口回調(diào)回來后,允許接口轉(zhuǎn)發(fā)到其他環(huán)境

實現(xiàn)思路:由于回調(diào)接口中是沒有參數(shù)能標識發(fā)到哪個環(huán)境,因此無法在nginx層面解決。就在具體服務(wù)上做:

  1. 接收請求,找到需要轉(zhuǎn)發(fā)到哪些環(huán)境

  1. 封裝請求,將回調(diào)請求轉(zhuǎn)發(fā)過去(header帶上標識:x-forward-from)

  1. 如果請求帶有x-forward-from,則不轉(zhuǎn)發(fā)

  1. 同時本服務(wù)也接收該請求并處理

這些邏輯都是和接口邏輯不相干的,因此考慮切面等方式處理,最后采用filter處理。邏輯在filter中處理

以下是遇到的相關(guān)問題:項目采取SpringMVC

Q:WebApplicationContext獲取HttpClient的bean失敗

call其他環(huán)境用封裝的HttpClient的bean,它是一個帶線程池的,filter通過在web.xml進行配置生效。如下:

NotifyMessageForwardFiltercom.lenovo.ofp.payment.front.webapp.filter.NotifyMessageForwardFilterNotifyMessageForwardFilter/notify/*

這種方式,可以看作是new NotifyMessageForwardFilter()。無法通過@Auwired 注入bean,會報錯。當然這個報錯具體原因是因為filter調(diào)用時,bean對象還沒初始化好:web.xml中各個標簽初始化的順序如下:contetxt-param ->listener ->filter ->servlet

用來加載你配置的文件信息配置你的監(jiān)聽服務(wù)過濾器配置你單獨的一些操作容器初始化
加載順序為:context-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()這個方法發(fā)現(xiàn),沒有HttpClient的bean,連Controller的bean都沒有。因此才認為,至少還有一個其他的ApplicationContext

而servlet的applicationContext的id是:org.springframework.web.context.WebApplicationContext:/payment-front-webapp/dispatcher

發(fā)現(xiàn)了吧,ApplicationContext不是一個,所以呀,我們要用下面那個。

A:解決方法:通過上面的分析,我們也知道ApplicationContext除了WebApplicationUtils獲取的那個外,還存在至少一個。所以用ApplicationContextAware來獲取。畢竟這個接口是在服務(wù)啟動完成后執(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)容的長度動態(tài)計算的。因此在請求轉(zhuǎn)發(fā)的時候,要刪掉

Q2:requestBody無法被重復(fù)讀取

請求轉(zhuǎn)發(fā)到不同環(huán)境,這意味著我們需要封裝http請求,需要讀取body。而body讀取一次后就會報錯。

A:body無法被重復(fù)讀取原因是body內(nèi)容放在InputStream中,這個流是只能讀一次的,根據(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:其實就是一個實現(xiàn)邏輯出錯。我們生成RequestWrapper后,應(yīng)當在filterChain里面?zhèn)魅隦equestWrapper而不是原來的request。其次是:RequestContextHolder,這個是在filter之前就設(shè)置了Request,所以有必要,需要更新里面的Request

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

網(wǎng)頁標題:第三方接口回調(diào)轉(zhuǎn)發(fā)到不同環(huán)境-創(chuàng)新互聯(lián)
網(wǎng)頁路徑:http://www.muchs.cn/article12/depsdc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站排名電子商務(wù)、虛擬主機、域名注冊、關(guān)鍵詞優(yōu)化、外貿(mào)建站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都seo排名網(wǎng)站優(yōu)化