使用ren專案來修改測試上一篇的商品分類功能,先啟動後端的ren-fast然後再啟動前端的ren-fast-vue

登入帳號(admin:admin),輸入驗證碼(如果沒有驗證碼表示後端有問題,要檢查),然後選擇系統管理 > 選單管理 > 新增

新增完成後則在DB:yumall-admin > sys_menu會出現剛新增的資料

接下來新增選單

重新整理後左側選單就會出現剛剛新增的分類維護選單和商品系統選單

接下來要瞭解一下ren專案的架構和規範,先看左側選單的角色管理,發現他的發的請求是sys-role,而剛新增的product/category會變成product-category,意思就是/會換成-

然而程式碼部分則是依照資料夾-檔案名稱.vue這樣分類,如圖顯示/src/views/modules/sys/role.vue

理解這其中的規範後,就再/modules/新增一個資料夾product和一個category.vue檔案,然後使用自定義的vue模版,新增後在<template>中新增elementUI的Tree

<el-tree :data="data" :props="defaultProps" @node-click="handleNodeClick"></el-tree>

參考role.vue中的getDataList()來寫

<script>
// 這裡可以載入其它文件 (例如:元件、JS檔、第三方套件、Json檔案、圖片...等)
// EX: import 元件名稱 from '元件路徑';

export default {
  // import載入的組件需要注入到物件中才能使用
  components: {},
  props: {},
  data() {
    return {
      data: [],
      defaultProps: {
        children: "children",
        label: "label",
      },
    };
  },
  methods: {
    handleNodeClick(data) {
      console.log(data);
    },
    getMeuns() {
        this.$http({
        url: this.$http.adornUrl("/product/category/list/tree"),
        method: "get",
      }).then((data) => {
        console.log("成功取得選單資料:", data);
      });
    }
  },
  // 計算屬性,類似於data的概念
  computed: {},
  // 監聽器,監聽資料有無變化
  watch: {},

  // 生命週期 - 建立完成 (可以訪問當前this實例)
  created() {
    this.getMeuns();  //  啟動時執行
  },
  // 生命週期 - 掛載完成 (可以訪問DOM元素)
  mounted() {},
  beforeCreate() {}, // 生命週期 - 建立前
  beforeMount() {}, // 生命週期 - 掛載前
  beforeUpdate() {}, // 生命週期 - 更新前
  updated() {}, // 生命週期 - 更新後
  beforeDestroy() {}, // 生命週期 - 銷毀前
  destroyed() {}, // 生命週期 - 已銷毀
  activated() {}, // 如果頁面有keep-alive緩衝功能,這個函數就會觸發
};
</script>

存檔後發現還是沒資料,使用瀏覽器開發者模式的Network頁籤檢查

發現請求的URL有錯
  1. URL不應該顯示renren-fast,且後台的port號是10000而前台發送的卻是8080

要先處理這問題要先找到這個地方從哪裡發起的,VScode全域搜尋(http://localhost:8080/renren-fast)找到了在/static/config/index.js

這裡是API請求的URL,需要改成API Gateway的URL:http://localhost:88/api,這樣所有請求都透過API Gateway來轉發給其他服務,如此一來就算port是8000、9000、10000都可以設定並轉發

儲存後測試時又發現了問題,系統要求重新登入,所以跳到登入頁面,但驗證碼卻消失了

因為URL不同,而ren project後台原先發送驗證碼的部分沒有修改,所以驗證碼一直無法顯示,要正常顯示必須先修改renren-fast的pom檔,加入之前設定好的common專案,要讓他註冊到服務中心

                <dependency>
			<groupId>com.cheng.yumall</groupId>
			<artifactId>yumall-common</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>

然後application.yml也要新增有關nacos的設定

  application:
    name: renren-fast
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

在啟動的class加入Annotation:@EnableDiscoveryClient

接下來

要在API Gateway中新增路由規則,這樣才能做到轉發,修改application.yml

...
...
#新增路由
        - id: admin_route
          uri: lb://renren-fast
          predicates:
            - Path=/api/**

上面的規則是參考Path Route Predicate Factory,這個路徑的斷言,也就是有URL前面是/api/的,不管斜線是什麼,都會轉送至renren-fast,而lb指的就是負載平衡,詳情可看官網連結

重啟renren-fast和yumallGetway再試試看

URL雖然改了,但還是404,這原因是因為預設的請求URL是應該是http://localhost:8080/renren-fast/captcha.jpg?uuid=xxxxxx

而修改後的URL沒有renren-fast設定的專案名稱,這部分的設定在application中的servlet

所以請求在經過API Gateway的時候必須要做路徑的重寫才行,要將http://localhost:88/api/captcha.jpg 改寫成 http://localhost:8080/renren-fast/captcha.jpg,這樣才對

一樣在API Gateway中的application.yml修改

        - id: admin_route
          uri: lb://renren-fast
          predicates:
            - Path=/api/**
          filters:
            - RewritePath=/api(?<segment>.*), /renren-fast/$\{segment}

有關filters的設定也參考官網連結,存檔後再重啟服務測試一次

現在看就有成功回應200了,來登入試試看,發現又有問題了!

Access to XMLHttpRequest at 'http://localhost:88/api/sys/login' from origin 'http://localhost:8001' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

這個錯誤是有關同源政策的原因,簡單的解釋就是瀏覽器對於JavaScript的安全限制,如果網域名稱和port不相同則會被認定是跨網域請求,另外也發現登入請求也未被送出,這個請求方式是OPTIONS,這是非簡單請求,這種請求都是要發送一個preflighted(預先檢查的請求),簡單解釋這情況就是瀏覽器發送非簡單請求時,會先發送預檢請求去詢問伺服器,如果伺服器回應允許才會發送資料,這是有關CORS的部分,就請參考MDN連結

要解決這種方式,有幾種方式,一種是用nginx讓前後台都部屬在其中,然後nginx再反向代理到其他服務,但開發期間要設定比較麻煩,第二種方式就讓伺服器回應允許跨域這樣就能正常回應

一樣在API Gateway中修改,新增package:config,在裡面新增一個class:CorsConfiguration

@Configuration
public class YuCorsConfiguration {

    @Bean
    public CorsWebFilter corsWebFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();

        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.setAllowCredentials(true);

        source.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsWebFilter(source);
    }
}

重啟服務再測試一次…還是出現了問題

Access to XMLHttpRequest at 'http://localhost:88/api/sys/login' from origin 'http://localhost:8001' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'http://localhost:8001, http://localhost:8001', but only one is allowed.

這裡指的是有重複出現的設定值,從發送請求的login頁面檢查看看

預檢請求有發送,然後Response Header 也是POST,這部分沒問題,但後面的請求就出現了問題

設定的值都設定了兩次,會發生這種情形的原因就是在後端除了剛新增的設定之外還有別的程式也設定了這些值,後來發現在renren-fast中src/main/java/io/renren/config/CorsConfig.java也有相關CORS的設定,只好先將裡面的設定值註解,然後重啟再一次的測試

登入成功也取到資料,終於成功了!