主頁 > 軟體設計 > 跨域:后端工程師最熟悉的陌生“人”

跨域:后端工程師最熟悉的陌生“人”

2023-01-13 06:59:37 軟體設計

摘要:跨域,對后端工程師來說,可謂既熟悉又陌生,

本文分享自華為云社區《后端老司機的跨域之旅》,作者: 勇哥java實戰分享,

跨域,對后端工程師來說,可謂既熟悉又陌生,

這兩個月我以架構師的角色參與一款教育產品的范訓,有了一段難忘的跨域之旅,

寫這篇文章,我想分享我在跨域這個知識點的經歷和思考,希望對大家有所啟發,

1 遇見跨域

產品有多端:機構端,局方端 ,家長端等 ,每端都有獨立的域名,有的是在PC上訪問,有的是通過微信公眾號來訪問,有的是掃碼后H5展現,

接入層呼叫的介面域名統一使用 api.training.com這個獨立的域名,通過Nginx來配置請求轉發,

通常,我們提到的跨域指:CORS,

CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing), 它需要瀏覽器和服務器同時支持他,允許瀏覽器向跨源服務器發送XMLHttpRequest請求,從而克服 AJAX 只能同源使用的限制,

那么如何定義同源呢?我們先看下一個典型的網站的地址:

同源是指:協議、域名、埠號完全相同,

下表給出了與 URL http://www.training.com/dir/page.html 的源進行對比的示例:

當用戶通過瀏覽器訪問應用(http://admin.training.com)時,呼叫介面的域名非同源域名(http://api.training.com),這是顯而易見的跨域場景,

2 CORS詳解

跨域資源共享標準新增了一組 HTTP 首部欄位,允許服務器宣告哪些源站通過瀏覽器有權限訪問哪些資源,

規范要求,對那些可能對服務器資料產生副作用的 HTTP 請求方法(特別是 GET 以外的 HTTP 請求,或者搭配某些 MIME 型別的 POST 請求),瀏覽器必須首先使用 OPTIONS 方法發起一個預檢請求(preflight request),從而獲知服務端是否允許該跨域請求,

服務器確認允許之后,才發起實際的 HTTP 請求,在預檢請求的回傳中,服務器端也可以通知客戶端,是否需要攜帶身份憑證(包括 Cookies 和 HTTP 認證相關資料),

2.1 簡單請求

當請求同時滿足如下條件時,CORS驗證機制會使用簡單請求, 否則CORS驗證機制會使用預檢請求,

1.使用GET、POST、HEAD其中一種方法;

2.只使用了如下的安全首部欄位,不得人為設定其他首部欄位;

    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type 僅限三種之一:text/plain,multipart/form-data,application/x-www-form-urlencoded:
    • HTML頭部 header field欄位:DPR、Download、Save-Data、Viewport-Width、WIdth

3.請求中的任意 XMLHttpRequestUpload 物件均沒有注冊任何事件監聽器;XMLHttpRequestUpload 物件可以使用 XMLHttpRequest.upload 屬性訪問;

4.請求中沒有使用 ReadableStream 物件,

簡單請求模式,瀏覽器直接發送跨域請求,并在請求頭中攜帶Origin的頭,表明這是一個跨域的請求, 服務器端接到請求后,會根據自己的跨域規則,通過Access-Control-Allow-Origin和Access-Control-Allow-Methods回應頭,來回傳驗證結果,

應答中攜帶了跨域頭 Access-Control-Allow-Origin,使用 Origin 和 Access-Control-Allow-Origin 就能完成最簡單的訪問控制,本例中,服務端回傳的 Access-Control-Allow-Origin: * 表明,該資源可以被任意外域訪問,如果服務端僅允許來自 http://admin.training.com 的訪問,該首部欄位的內容如下:

Access-Control-Allow-Origin: http://admin.training.com

現在,除了 http://admin.training.com,其它外域均不能訪問該資源,

2.2 預檢請求

瀏覽器在發現頁面發出的請求非簡單請求,并不會立即執行對應的請求代碼,而是會觸發預先請求模式,預先請求模式會先發送preflight request(預先驗證請求),preflight request是一個OPTION請求,用于詢問要被跨域訪問的服務器,是否允許當前域名下的頁面發送跨域的請求,在得到服務器的跨域授權后才能發送真正的HTTP請求,

OPTIONS請求頭部中會包含以下頭部:

服務器收到OPTIONS請求后,設定頭部與瀏覽器溝通來判斷是否允許這個請求,

如果preflight request驗證通過,瀏覽器才會發送真正的跨域請求,

3 后端配置

后端配置我嘗試過兩種方式,經過兩個月的測驗,都能非常穩定的運行,

  • MND推薦的Nginx配置;
  • SpringBoot自帶CorsFilter配置,

▍MND推薦的Nginx配置

Nginx配置相當于在請求轉發層配置,

location / {
 if ($request_method = 'OPTIONS') {
 add_header 'Access-Control-Allow-Origin' '*';
 add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
 #
 # Custom headers and headers various browsers *should* be OK with but aren't
 #
 add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
 #
 # Tell client that this pre-flight info is valid for 20 days
 #
 add_header 'Access-Control-Max-Age' 1728000;
 add_header 'Content-Type' 'text/plain; charset=utf-8';
 add_header 'Content-Length' 0;
 return 204;
 }
 if ($request_method = 'POST') {
 add_header 'Access-Control-Allow-Origin' '*' always;
 add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
 add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
 add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
 }
 if ($request_method = 'GET') {
 add_header 'Access-Control-Allow-Origin' '*' always;
 add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
 add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
 add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
 }
}

在配置Access-Control-Allow-Headers屬性的時候,因為自定義的header包含簽名和token,數量較多,為了簡潔方便,我把Access-Control-Allow-Headers配置成 * ,

在Chrome和firefox下沒有任何例外,但在IE11下報了如下的錯:

Access-Control-Allow-Headers 串列中不存在請求標頭 content-type,

原來IE11要求預檢請求回傳的Access-Control-Allow-Headers的值必須以逗號分隔,

▍SpringBoot自帶CorsFilter

首先基礎框架里默認有如下跨域配置,

public void addCorsMappings(CorsRegistry registry) {
 registry.addMapping("/**")
 .allowedOrigins("*")
 .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
 .allowCredentials(true)
 .allowedHeaders("*")
 .maxAge(3600);
}

可是部署完成,進入還是報CORS例外:

從nginx和tomcat日志來看,僅僅收到一個OPTION請求,springboot應用里有一個攔截器ActionInterceptor,從header中獲取token,呼叫用戶服務查詢用戶資訊,放入request中,當沒有獲取token資料時,會回傳給前端JSON格式資料,

但從現象來看CorsMapping并沒有生效,

為什么呢?實際上還是執行順序的概念,下圖展示了 過濾器,攔截器,控制器的執行順序,

DispatchServlet.doDispatch()方法是SpringMVC的核心入口方法,

// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
 return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

那么CorsMapping在哪里初始化的呢?經過除錯,定位于AbstractHandlerMapping

protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
HandlerExecutionChain chain, CorsConfiguration config) {
if (CorsUtils.isPreFlightRequest(request)) {
HandlerInterceptor[] interceptors = chain.getInterceptors();
chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
}
else {
chain.addInterceptor(new CorsInterceptor(config));
 }
return chain;
}

代碼里有預檢判斷,通過PreFlightHandler.handleRequest()中處理,但是處于正常的業務攔截器之后,

最終選擇CorsFilter 主要基于兩點原因:

  • 過濾器的執行順序優先級最高;
  • 通過除錯CorsFilter的原始碼,發現原始碼有很多細節的處理,
private CorsConfiguration corsConfig() {
 CorsConfiguration corsConfiguration = new CorsConfiguration();
 corsConfiguration.addAllowedOrigin("*");
 corsConfiguration.addAllowedHeader("*");
 corsConfiguration.addAllowedMethod("*");
 corsConfiguration.setAllowCredentials(true);
 corsConfiguration.setMaxAge(3600L);
 return corsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
 source.registerCorsConfiguration("/**", corsConfig());
 return new CorsFilter(source);
}

下面的代碼里,allowHeader是通配符 * 的時候,CorsFilter在設定 Access-Control-Allow-Headers 的時候,會將 Access-Control-Request-Headers 以逗號拼接起來,這樣就可以避免IE11回應頭的問題,

public List<String> checkHeaders(@Nullable List<String> requestHeaders) {
 if (requestHeaders == null) {
 return null;
 }
 if (requestHeaders.isEmpty()) {
 return Collections.emptyList();
 }
 if (ObjectUtils.isEmpty(this.allowedHeaders)) {
 return null;
 }
 boolean allowAnyHeader = this.allowedHeaders.contains(ALL);
   List<String> result = new ArrayList<>(requestHeaders.size());
 for (String requestHeader : requestHeaders) {
 if (StringUtils.hasText(requestHeader)) {
 requestHeader = requestHeader.trim();
 if (allowAnyHeader) {
 result.add(requestHeader);
 }
 else {
 for (String allowedHeader : this.allowedHeaders) {
 if (requestHeader.equalsIgnoreCase(allowedHeader)) {
 result.add(requestHeader);
 break;
 }
 }
 }
 }
 }
 return (result.isEmpty() ? null : result);
}

瀏覽器的執行效果如下:

4 preflight回應碼:200 vs 204

后端配置完成之后,團隊里的小伙伴問我:“勇哥,那預檢請求回傳的回應碼到底是200還是204呀?”,這個問題真把我給問住了,

我司的API網關的預檢回應碼是200,CorsFilter預檢回應碼也是200,

MDN給的示例預檢回應碼全部是204,

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

我只能采取Google大法,赫然發現大名鼎鼎的API網關Kong的開發者也針對這個問題有一番討論,

  1. MDN曾經推薦的preflight回應碼是200 ,所以Kong也和MDN同步成200;
    The page was updated since then. See its contents on Sept 30th, 2018:
    https://web.archive.org/web/20180930031917/https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
  2. 后來MDN將回應碼修改204,于是Kong的開發者爭論要不要和MDN保持同步,
    爭論的核心點在于:有沒有迫切的必要,200回應碼運行得很好,似乎也將永遠正常運行下去,而更換成204,不確定是否有隱藏問題,
  3. 說到底,框架開發者還是依賴于瀏覽器的底層實作,在這個問題上,沒有足夠權威的資料能夠支撐框架開發者,而各個知識點都散落在網路的各個角落,充斥著不完整的細節和部分解決方案,這些都讓框架開發者非常困惑,

最后,Kong的原始碼里預檢回應碼仍然是200,并沒有和MDN保持同步,

我仔細查看了各大主流網站,95%預檢回應碼是200,而經過兩個多月的測驗,Nginx配置預檢回應碼204,在主流的瀏覽器Chrome , Firefox , IE11 也沒有出現任何問題,

所以,200 works everywhere , 而204在當前主流的瀏覽器里也得到非常好的支持,

5 Chrome: 非安全私有網路

本以為跨域問題就這樣解決了,沒想到還是有一個小插曲,

產品總監需要給客戶做演示,我負責搞定演示環境,申請域名,準備阿里云服務器,應用打包,部署,一切都很順利,

可是在公司內網訪問演示環境,有一個頁面一直報CORS報錯,報錯內容類似下圖:

跨域的錯誤型別是:InsecurePrivateNetwork,

這和原來遇到的跨域錯誤完全不一樣,我心里一慌,馬上Google , 原來這是chrome更新到94之后新的特性,可以手工關閉這個特性,

  1. 打開 tab 頁面 chrome://flags/#block-insecure-private-network-requests
  2. 將其 Block insecure private network requests 設定為 Disabled, 然后重啟就行了, 這樣子就相當于把這個功能禁用掉,

但這樣是治標不治本呀,有點詭異的是,當我們不在公司內網訪問演示環境的時候,演示環境完全正常,出錯的頁面也能正常訪問,

仔細看官方的檔案,CORS-RFC1918 指出如下三種請求會受影響,

  • 公共網路訪問私有網路;
  • 公共網路訪問本地設備;
  • 私有網路訪問本地設備,

這樣,我把問題定位在這個出錯的第三方介面地址上,公司很多產品都依賴這個介面服務,當在公司內網訪問的時候,該域名映射地址類似:172.16.xx.xx,

而這個ip正好是rfc1918上規定的私有網路,

10.0.0.0     -  10.255.255.255 (10/8 prefix)
172.16.0.0   -  172.31.255.255 (172.16/12 prefix)
192.168.0.0  - 192.168.255.255 (192.168/16 prefix)

內網通過Chrome訪問這個頁面的時候,會觸發非安全私有網路攔截,

如何解決呢?官方給出的方案分兩步走:

  1. 私有網路只能通過Https來訪問;
  2. 未來,添加特定的預檢頭,比如說:Access-Control-Request-Private-Network等,

當然還有一些臨時方法:

  • 關閉Chrome該特性;
  • 換用其他瀏覽器比如Firefox;
  • 關閉網路內網開手機熱點;
  • 修改本地host系結外網ip,

基于官方的方案 ,生產環境完全使用Https,公司內網訪問就沒有出現這樣的跨域問題了,

6 復盤

API網關非常適合當前產品的架構,架構設計之初,系統多端都會呼叫我司的API網關,API網關可以SAAS部署和私有化部署,有單獨的域名,提供完善的簽名演算法,考慮到上線時間節點,團隊成員對于API網關的熟悉程度以及多套環境部署投入時間成本,為了盡快交付,從架構層面,我做了一些平衡和妥協,

接入層呼叫的介面域名統一使用 api.training.com這個獨立的域名,通過Nginx來配置請求轉發,同時,我和前端Leader統一了前后端協議,保持和我司API網關一致,為后續切回API網關做前置準備,

API網關可以做鑒權,限流,灰度等,同時可以配置CORS,內部服務端不用特別關注跨域這個問題,

同時,在解決跨域的問題程序中,我的心態也發生了變化,從最初的輕視,到逐漸沉下心來,一步步理解CORS的原理,分清楚不同解決方案的優缺點,事情也就慢慢順遂起來, 我也觀察到:”有的專案組已經反饋過Chrome非安全私有網路問題,并給出了解決方案,對于技術管理者來講,一定要重視專案中反饋的問題,做好梳理分析,整理預案,這樣當同類問題出現時,也會條理有序“,

 

點擊關注,第一時間了解華為云新鮮技術~

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/541896.html

標籤:架構設計

上一篇:作業流引擎架構設計

下一篇:讀編程與型別系統筆記05_函式型別

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more