欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

springboot中請(qǐng)求地址轉(zhuǎn)發(fā)的兩種方案

 更新時(shí)間:2023年11月24日 15:29:02   作者:Mr.var  
在開(kāi)發(fā)過(guò)程中,我們經(jīng)常需要將請(qǐng)求從一個(gè)服務(wù)轉(zhuǎn)發(fā)到另一個(gè)服務(wù),以實(shí)現(xiàn)不同服務(wù)之間的協(xié)作,本文主要介紹了springboot中請(qǐng)求地址轉(zhuǎn)發(fā)的兩種方案,感興趣的可以了解一下

一、背景需求

現(xiàn)有一個(gè)平臺(tái),如果在上面發(fā)布軟件,需要在平臺(tái)注冊(cè)所有的接口,注冊(cè)好后平臺(tái)會(huì)給每一個(gè)接口都提供一個(gè)不同的新地址(所有的請(qǐng)求在平臺(tái)注冊(cè)后都是類(lèi)似"http://localhost:8080/{appkey}/{token}"的格式,每個(gè)接口都擁有一個(gè)不同的appkey作為標(biāo)識(shí),token可通過(guò)另一個(gè)請(qǐng)求獲?。?,在前端調(diào)用請(qǐng)求的時(shí)候,必須請(qǐng)求平臺(tái)提供的地址,然后平臺(tái)會(huì)替前端轉(zhuǎn)發(fā)到真實(shí)的地址去請(qǐng)求后端。

為了減少注冊(cè)和審核的工作量,我們可以只注冊(cè)少量接口,然后在這些接口內(nèi)我們自行轉(zhuǎn)發(fā)。

二、方案一

zuul轉(zhuǎn)發(fā):

在平臺(tái)注冊(cè)增刪改查等若干個(gè)虛擬的接口地址,然后在前端將所有接口封裝成這些虛擬接口,并在請(qǐng)求參數(shù)內(nèi)傳遞真實(shí)的接口地址,通過(guò)平臺(tái)轉(zhuǎn)發(fā)到后端之后我們通過(guò)zuul過(guò)濾器再轉(zhuǎn)發(fā)到自己真實(shí)的接口地址上。(注:登錄接口比較特殊,登錄在后端是寫(xiě)在主服務(wù)內(nèi)的,zuul網(wǎng)關(guān)不會(huì)進(jìn)行攔截,這里單獨(dú)注冊(cè);其余接口統(tǒng)一寫(xiě)在同一個(gè)服務(wù)內(nèi),便于統(tǒng)一轉(zhuǎn)發(fā)配置)

前端代碼演示:

這里是在vue中寫(xiě)的一個(gè)axios的請(qǐng)求攔截器,統(tǒng)一對(duì)真實(shí)接口進(jìn)行封裝
舉個(gè)例:
我們?cè)谄脚_(tái)上注冊(cè)一個(gè)虛擬地址:
http://localhost:8080/comSelect/getData
=>
注冊(cè)后請(qǐng)求地址變?yōu)椋?br />http://xxx.xxx.xxx:xxxx/appKeySelect123/{token}

axios.interceptors.request.use(
	config => {
		if (!config.url.startsWith("http")) {
			    //模擬一個(gè)token,真實(shí)token可通過(guò)平臺(tái)提供的另一請(qǐng)求獲取
				let token = "token";
				
				//將接口地址放在covertUrl參數(shù)內(nèi)傳遞給后端
				if (config.method == "post") {
				    //post請(qǐng)求的兩種content-type格式
					if (typeof config.data == "string") {
						//請(qǐng)求參數(shù)表單格式
						//qs可用于格式化參數(shù)
						let conData = qs.parse(config.data);
						conData.covertUrl = config.url;

						config.data = qs.stringify(conData);
					} else {
						//請(qǐng)求體格式
						config.data.covertUrl = config.url;
					}
				} else if (config.method == "get"){
				    //axios中g(shù)et請(qǐng)求可用params指定url傳值
					config.params.covertUrl = config.url;
				}

                //封裝成平臺(tái)要求的請(qǐng)求地址,真實(shí)的url存于參數(shù)covertUrl中
				config.url = urlPack(token, config.url);
		}
		return config;
	},
	error => {
		return Promise.reject(error);
	}
);

//接口地址封裝,將所有接口統(tǒng)一分為增刪改查四個(gè)接口
function urlPack(token, url) {
	let appKey;
	//登陸
	let appKeyLogin = "/appKeyLogin123/";
	//增
	let appKeyAdd = "/appKeyAdd123/";
	//刪
	let appKeyDelete = "/appKeyDelete123/";
	//改
	let appKeyUpdate = "/appKeyUpdate123/";
	//查
	let appKeySelect = "/appKeySelect123/";  //http://localhost:8080/comSelect/getData 

    //隨便拿幾個(gè)接口舉例
	switch (url) {
		case "/sysUser/app_login":
			appKey = appKeyLogin;
			break;
		case "/appcommon/appVersion/getVersion":
			appKey = appKeySelect;
			break;
		case "/appcommon/appMenu/getMenu":
			appKey = appKeySelect;
			break;
	}

	return "http://localhost:8080" + appKey + token;
}

后端代碼演示:

#這里需要注意,必須在zuul的路由配置里添加平臺(tái)轉(zhuǎn)發(fā)之后傳遞過(guò)來(lái)的虛擬路由,不然zuul會(huì)報(bào)出找不到路由的錯(cuò)
zuul:
  #路由添加
  routes:
    #虛擬服務(wù)地址
    comSelect:
      path: /comSelect/**
    #真實(shí)的路由服務(wù),這里的地址是真實(shí)注冊(cè)到了eureka的服務(wù)地址,也可以動(dòng)態(tài)獲取
    appcommon:
      path: /appcommon/**
      serviceId: appcommon
/**
 * 轉(zhuǎn)換成真正的url地址,路由轉(zhuǎn)發(fā)
 */
@Slf4j
@Component
public class ZuulAppRouteFilter extends ZuulFilter {
    /**
     * filterType:返回一個(gè)字符串代表過(guò)濾器的類(lèi)型,在zuul中定義了四種不同生命周期的過(guò)濾器類(lèi)型,具體如下:
     *     pre:路由之前
     *     routing:路由之時(shí)
     *     post: 路由之后
     *     error:發(fā)送錯(cuò)誤調(diào)用
     */
    @Override
    public String filterType() {
        return FilterConstants.ROUTE_TYPE;
    }

    /**
     * 過(guò)濾器優(yōu)先級(jí),同一filterType下的過(guò)濾器,數(shù)值越大優(yōu)先級(jí)越低
     */
    @Override
    public int filterOrder() {
        return 1;
    }

    /**
     * 是否啟用過(guò)濾器,這里可以做一些邏輯判斷
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {

        RequestContext ctx = RequestContext.getCurrentContext();

        HttpServletRequest request = ctx.getRequest();
        //真正的接口地址
        String path = "";

        try {
            //請(qǐng)求參數(shù)(url傳值或表單傳值)
            Map<String, String[]> parameterMap = request.getParameterMap();
            //請(qǐng)求參數(shù)(請(qǐng)求體)
            String requestBody = null;
            try {
                requestBody = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (parameterMap.size() == 0) {
                if (requestBody != null && !"".equals(requestBody)) {
                    try {
                        JSONObject jsonObj = JSONObject.parseObject(requestBody);

                        if (jsonObj.get("covertUrl") != null) {
                            Object covertUrl = jsonObj.get("covertUrl");
                            path = String.valueOf(covertUrl);
                        }
                    } catch (Exception e) {
                        log.error("path[" + path + "]返回的不是json格式數(shù)據(jù),返回信息:" + requestBody);
                    }
                }
            } else {
                if (parameterMap.get("covertUrl") != null) {
                    String[] description = parameterMap.get("covertUrl");
                    path = URLDecoder.decode(description[0]);
                }
            }
            
            //所有的服務(wù)全部指向serviceId為appcommon這個(gè)路由
            //如果需要轉(zhuǎn)發(fā)到其他服務(wù)則通過(guò)判斷path來(lái)寫(xiě)判斷
            String serviceId = "";
            if (path.contains("appcommon")) {
                    serviceId = "appcommon";
             } else if (path.contains("sync")) {
                    serviceId = "sync";
            }
            //請(qǐng)求地址轉(zhuǎn)發(fā)到真實(shí)的接口上
            ctx.put(FilterConstants.REQUEST_URI_KEY, path);

        } catch (Exception ignored) {
            log.error(request.getRequestURL().toString() + "解析失敗");
        }

        return null;
    }
}

三、方案二:

java反射:

在平臺(tái)注冊(cè)增刪改查等若干個(gè)接口地址,并在后端編寫(xiě)這些接口作為統(tǒng)一分發(fā)接口,然后在前端將所有接口封裝成這些接口,并在請(qǐng)求參數(shù)內(nèi)傳遞接口的類(lèi)名和對(duì)應(yīng)的方法名,通過(guò)平臺(tái)轉(zhuǎn)發(fā)傳遞到后端之后,后端利用Java的反射機(jī)制調(diào)用真實(shí)的接口地址,轉(zhuǎn)發(fā)到對(duì)應(yīng)的接口上。

前端代碼演示:

舉個(gè)例:
我們?cè)谄脚_(tái)上注冊(cè)的地址:
http://localhost:8080/appcommon/common/query
=>
注冊(cè)后請(qǐng)求地址變?yōu)椋?br />http://localhost:8080/appKeySelect123/{token}

axios.interceptors.request.use(
	config => {
		if (!config.url.startsWith("http")) {
			    //模擬一個(gè)token,真實(shí)token可通過(guò)平臺(tái)提供的另一請(qǐng)求獲取
				let token = "token";
				
				let req;
				if (config.method == "post") {
					if (typeof config.data == "string") {
						//請(qǐng)求參數(shù)表單格式
						let conData = qs.parse(config.data);

						config.data = qs.stringify(conData);

						req = reqPack(token, config.url, config.data);

						config.url = req.url;
						config.data = req.reqData;
					} else {
						//請(qǐng)求體格式
						req = reqPack(token, config.url, config.data);
						config.url = req.url;
						config.data = req.reqData;
					}
				} else {
					req = reqPack(token, config.url, config.params);
					
					config.url = req.url;
					config.params = req.reqData;
				}

                //封裝成平臺(tái)要求的請(qǐng)求地址,真實(shí)的url存于參數(shù)covertUrl中
				config.url = urlPack(token, config.url);
		}
		return config;
	},
	error => {
		return Promise.reject(error);
	}
);

//接口地址封裝,將所有接口統(tǒng)一分為增刪改查四個(gè)接口
function urlPack(token, url, data) {
	//總線所需的key
	let appKey;
	//登陸
	let appKeyLogin = "/appKeyLogin123/";
	//增
	let appKeyAdd = "/appKeyAdd123/";
	//刪
	let appKeyDelete = "/appKeyDelete123/";
	//改
	let appKeyUpdate = "/appKeyUpdate123/";
	//查
	let appKeySelect = "/appKeySelect123/";  //http://localhost:8080/appcommon/common/query

	//請(qǐng)求參數(shù)
	let reqData = {
		//類(lèi)名
		className: "",
		//方法名
		methodName: "",
		//接口所需參數(shù)
		params: data
	}
	
	//指定不同接口的類(lèi)名和方法名,用于分發(fā)調(diào)用
	switch (url) {
	    //登錄請(qǐng)求比較特殊,單獨(dú)注冊(cè),參數(shù)不封裝
		case "/sysUser/app_login":
			appKey = appLogin;
			return {
				url: GLOBAL.$RequestBaseUrl1 + appKey,
				reqData: data
			}
			break;
		case "/appcommon/appVersion/getVersion":
			appKey = appKeySelect;
			reqData.className = "AppVersionController";
			reqData.methodName = "getAppVersion";
			break;
		case "/sync/risk/road/getAllRoad":
			appKey = appKeySelect;
			break;
		case "/appcommon/appMenu/getMenu":
			appKey = appKeySelect;
			reqData.className = "AppMenuController";
			reqData.methodName = "getMenu";
			break;
	}

	return {
		url: GLOBAL.$RequestBaseUrl1 + appKey + token,
		reqData: reqData
	};
}

后端代碼演示:

/**
 * 公共接口實(shí)例
 */
@Data
public class CommonObj {
    /**
     * 類(lèi)名
     */
    private String className;
    /**
     * 方法名
     */
    private String methodName;
    /**
     * 實(shí)際參數(shù)
     */
    private Map<String,Object> params;
}
/**
 * Spring定義的類(lèi)實(shí)現(xiàn)ApplicationContextAware接口會(huì)自動(dòng)的將應(yīng)用程序上下文加入
 */
@Slf4j
@Component
public class MySpringUtil implements ApplicationContextAware {
    //上下文對(duì)象實(shí)例
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (MySpringUtil.applicationContext == null) {
            MySpringUtil.applicationContext = applicationContext;
        }
    }

    //獲取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    //通過(guò)name獲取 Bean.
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    //通過(guò)class獲取Bean.
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    //通過(guò)name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }

}
/**
 * app公共接口調(diào)用,通過(guò)反射分發(fā)調(diào)用接口
 *
 * @author xht
 */
@RestController
@RequestMapping("/common")
@Slf4j
public class CommonController {

    /**
     * 利用反射調(diào)用接口
     */
    public Response reflectControl(CommonObj commonObj){
        String className = commonObj.getClassName();
        String methodName = commonObj.getMethodName();
        Map<String, Object> params = commonObj.getParams();

        Response response;
        try {
            //1、獲取spring容器中的Bean
            //類(lèi)名首字母小寫(xiě)
            className = StringUtils.uncapitalize(className);
            Object proxyObject = MySpringUtil.getBean(className);
            //2、利用bean獲取class對(duì)象,進(jìn)而獲取本類(lèi)以及父類(lèi)或者父接口中所有的公共方法(public修飾符修飾的)
            Method[] methods = proxyObject.getClass().getMethods();
            //3、獲取指定的方法
            Method myMethod = null;
            for (Method method : methods) {
                if (method.getName().equalsIgnoreCase(methodName)) {
                    myMethod = method;
                    break;
                }
            }
            //4、封裝方法需要的參數(shù)
            if (myMethod != null) {
                Object resObj;
                resObj = myMethod.invoke(proxyObject, params);

                response = (Response) resObj;
            } else {
                response = Response.error("未找到對(duì)應(yīng)方法");
            }
        } catch (Exception e) {
            e.printStackTrace();
            response = Response.error(e.getMessage());
        }
        return response;
    }

    /**
     * 公共新增接口
     */
    @PostMapping("/add")
    public Response commonAdd(@RequestBody CommonObj commonObj) {
        return reflectControl(commonObj);
    }
    /**
     * 公共刪除接口
     */
    @PostMapping("/delete")
    public Response commonDelete(@RequestBody CommonObj commonObj) {
        return reflectControl(commonObj);
    }
    /**
     * 公共修改接口
     */
    @PostMapping("/edit")
    public Response commonEdity(@RequestBody CommonObj commonObj) {
        return reflectControl(commonObj);
    }
    /**
     * 公共查詢(xún)接口
     */
    @PostMapping("/query")
    public Response commonQuery(@RequestBody CommonObj commonObj) {
        return reflectControl(commonObj);
    }
}

到此這篇關(guān)于springboot中請(qǐng)求地址轉(zhuǎn)發(fā)的兩種方案的文章就介紹到這了,更多相關(guān)springboot 請(qǐng)求地址轉(zhuǎn)發(fā)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • 詳解Java中LinkedStack鏈棧的實(shí)現(xiàn)

    詳解Java中LinkedStack鏈棧的實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了Java中LinkedStack鏈棧的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Java有一定幫助,需要的可以參考一下
    2022-11-11
  • Java中instanceOf關(guān)鍵字的用法及特性詳解

    Java中instanceOf關(guān)鍵字的用法及特性詳解

    當(dāng)我們?cè)谶M(jìn)行向下轉(zhuǎn)型時(shí),如果兩個(gè)對(duì)象之間沒(méi)有直接或間接的繼承關(guān)系,在轉(zhuǎn)換時(shí)有可能會(huì)產(chǎn)生強(qiáng)制類(lèi)型轉(zhuǎn)換異常,我們可以使用java中自帶的instanceOf關(guān)鍵字來(lái)解決這個(gè)問(wèn)題,所以本篇文章,會(huì)帶大家學(xué)習(xí)instanceOf的用法及特性,需要的朋友可以參考下
    2023-05-05
  • 詳解java面試題中的i++和++i

    詳解java面試題中的i++和++i

    這篇文章主要介紹了java面試題中的i++和++i的相關(guān)資料,需要的朋友可以參考下
    2018-03-03
  • Java8中的Stream流式操作教程之王者歸來(lái)

    Java8中的Stream流式操作教程之王者歸來(lái)

    這篇文章主要給大家介紹了關(guān)于Java8中Stream流式操作的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Java8具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • java學(xué)習(xí)DongTai被動(dòng)型IAST工具部署過(guò)程

    java學(xué)習(xí)DongTai被動(dòng)型IAST工具部署過(guò)程

    被動(dòng)型IAST被認(rèn)為是DevSecOps測(cè)試階段實(shí)現(xiàn)自動(dòng)化安全測(cè)試的最佳工具,而就在前幾天,洞態(tài)IAST正式開(kāi)源了,這對(duì)于甲方構(gòu)建安全工具鏈來(lái)說(shuō),絕對(duì)是一個(gè)大利好
    2021-10-10
  • idea如何添加文檔注釋

    idea如何添加文檔注釋

    這篇文章主要介紹了idea如何添加文檔注釋,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2024-06-06
  • Mybatis重置Criteria的正確姿勢(shì)分享

    Mybatis重置Criteria的正確姿勢(shì)分享

    這篇文章主要介紹了Mybatis重置Criteria的正確姿勢(shì),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • java動(dòng)態(tài)代理示例分享

    java動(dòng)態(tài)代理示例分享

    這篇文章主要介紹了java動(dòng)態(tài)代理示例,需要的朋友可以參考下
    2014-02-02
  • 淺析Java中SimpleDateFormat為什么是線程不安全的

    淺析Java中SimpleDateFormat為什么是線程不安全的

    SimpleDateFormat是Java中用于日期時(shí)間格式化的一個(gè)類(lèi),它提供了對(duì)日期的解析和格式化能力,本文主要來(lái)和大家一起探討一下SimpleDateFormat為什么是線程不安全的,感興趣的可以了解下
    2024-02-02
  • java.lang.annotation包詳細(xì)介紹

    java.lang.annotation包詳細(xì)介紹

    java.lang.annotation?包是 Java 標(biāo)準(zhǔn)庫(kù)中的一個(gè)核心包,專(zhuān)門(mén)用于定義和支持 Java 注解(Annotation),這篇文章主要介紹了java.lang.annotation包介紹,需要的朋友可以參考下
    2024-07-07

最新評(píng)論