最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

你不知道的SpringBoot與Vue部署解決方案

 更新時(shí)間:2020年11月09日 09:28:57   作者:張攀欽  
這篇文章主要介紹了你不知道的SpringBoot與Vue部署解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

前段時(shí)間公司外網(wǎng)部署的演示環(huán)境全部轉(zhuǎn)到內(nèi)網(wǎng)環(huán)境中去,所有對(duì)外演示的環(huán)境都需要申請(qǐng)外網(wǎng)映射才能訪問某個(gè)服務(wù)。我用一個(gè)外網(wǎng)地址 www.a.com 映射到一個(gè)內(nèi)網(wǎng)地址 http://ip:port ,然后在這個(gè)地址 http://ip:port 用 nginx 做代理轉(zhuǎn)發(fā)到各個(gè)組的項(xiàng)目 http://ipn:portn 上去,其中也遇到一些靜態(tài)資源 404,主要是是解決這個(gè) 404 問題。

最近又做了一個(gè)項(xiàng)目,考慮到用戶的體驗(yàn),減少部署的復(fù)雜性,我想了一個(gè)辦法用 SpringBoot 做 web 服務(wù)器映射前端資源為 web 資源 。

條件允許或者對(duì)性能要求比較高,推薦是前后端分離部署,nginx 做 web 服務(wù)器,后端只提供接口服務(wù)

以前部署的項(xiàng)目 A 外網(wǎng)訪問地址是 http://ip1:8080 ,外網(wǎng)映射后只能訪問 http://ip/app1 ,以前項(xiàng)目 B 外網(wǎng)訪問地址是 http://ip1:8081 ,項(xiàng)目訪問地址是 http://ip/app2 。這也算是一個(gè)不大不小的變動(dòng),但是切換之后遇到的第一個(gè)問題就是靜態(tài)資源轉(zhuǎn)發(fā)導(dǎo)致 404

比如以前項(xiàng)目 A 訪問地址是 http://ip1:8080 它是沒有上下文的。

而現(xiàn)在 A 的訪問地址為 http://ip/app1 ,有一個(gè)上下文 app1 在這里,導(dǎo)致有一些資源 404。

比如說:原來 http://ip1:8080 請(qǐng)求到了 index.html 資源,現(xiàn)在只能 http://ip/app1 請(qǐng)求到 index.html。

<!-- index.html -->
<!-- 原來部署環(huán)境寫法 -->
<link href="/index.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet">

以前訪問 index.css 地址是 http://ip1:8080/index.css ,但是現(xiàn)在變成訪問了 http://ip/index.css 導(dǎo)致 404,實(shí)際 index.css 地址為 http://ip/app1/index.css

前端使用 vue 編寫,html 中的靜態(tài)資源路徑可以很好解決,修改 webpack 打包即可。

<!-- 原來部署環(huán)境寫法 -->
<link href="/index.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet">

<!-- 寫成相對(duì)路徑 -->
<link href="./index.css" rel="external nofollow" rel="stylesheet">

<!-- 結(jié)合 webpack 打包時(shí)進(jìn)行路徑補(bǔ)充 -->
<link href="<%= BASE_URL %>index.css" rel="external nofollow" rel="stylesheet">

但是項(xiàng)目中有一些組件的請(qǐng)求沒有辦法統(tǒng)一處理,只能改代碼。但我不想動(dòng)代碼,webpack 打包都不想動(dòng),基于這些需求想了一個(gè)辦法來解決。

本文內(nèi)容

  • Nginx 部署 vue 項(xiàng)目,怎么能友好處理靜態(tài)資源的丟失
  • SpringBoot 提供 web 服務(wù)器的功能映射 vue 項(xiàng)目為 web 資源,并處理 vue 路由轉(zhuǎn)發(fā) index.html 問題。

演示代碼地址

Nginx 部署 Vue 項(xiàng)目

server {
  listen 8087;
  # 它的作用是不重定向地址,比如瀏覽器輸入 /app1 訪問,也可以訪問到 /app1/ ,而瀏覽器地址是不改變的 /app1 。沒辦法,強(qiáng)迫癥
  location / {
    try_files $uri $uri/;
  }
  root /Users/zhangpanqin/staic/;
  location ~ /(.*)/ {
    index index.html /index.html;
    try_files $uri $uri/ /$1/index.html;
  }
}

/Users/zhangpanqin/staic/ 放部署的項(xiàng)目,比如 app 的項(xiàng)目資源放到 /Users/zhangpanqin/staic/app 下。 訪問地址為 http://ip/8087/app

<!DOCTYPE html>
<html lang="en">
<head>
  <!-- 也可以改成類似的地址 BASE_URL 等于 vue.config.js 配置的 publicPath-->
  <link rel="icon" href="<%= BASE_URL %>favicon.ico" rel="external nofollow" >
  <!-- 部署之后,訪問不到 index.css -->
  <link href="/index.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet">
</head>
</html>

為了可以在瀏覽器輸入 vue 的路由 /app/blog 也可以訪問頁(yè)面,需要添加 vue-router 中的 base 屬性。

import Vue from 'vue';
import VueRouter from 'vue-router';

Vue.use(VueRouter);

const routes = [
  {
    path: '/',
    name: 'Home',
    component: () => import('@/views/Home.vue'),
  },
  {
    path: '/blog',
    name: 'Blog',
    component: () => import('@/views/Blog.vue'),
  },
  {
    // 匹配不到路由的時(shí)候跳轉(zhuǎn)到這里
    path: '*',
    name: 'Error404',
    component: () => import('@/views/Error404.vue'),
  }
];
const router = new VueRouter({
  // 主要是修改這里,可以根據(jù) vue mode 環(huán)境來取值。
  // https://cli.vuejs.org/zh/guide/mode-and-env.html
  // https://router.vuejs.org/zh/api/#base
  base: process.env.VUE_APP_DEPLOY_PATH,
  mode: 'history',
  routes,
});

export default router;

http://localhost:8087/app/index.css 為 css 的真實(shí)地址。所以想辦法為這些不以 /app 開頭的資源加上 /app 就可以了,想了想只有 cookie 能做到。

x_vue_path 記錄每個(gè)項(xiàng)目的路徑,然后靜態(tài)資源去這個(gè)路徑下尋找, $cookie_x_vue_path/$uri

下面這個(gè)配置使用了 try_files 內(nèi)部重定向資源,是不會(huì)在瀏覽器端發(fā)生重定向的。

# gzip ,緩存 和 epoll 優(yōu)化的都沒寫
server {
  listen 8087;
  # 它的作用是不重定向地址,比如瀏覽器輸入 /app1 訪問,也可以訪問到 /app1/ ,而瀏覽器地址是不改變的 /app1 。沒辦法,強(qiáng)迫癥
  location / {
    try_files $uri $uri/;
  }
  root /Users/zhangpanqin/staic/;

  # (.*) 匹配是哪個(gè)項(xiàng)目,比如說 app1 app2 等
  location ~ /(.*)/.*/ {
    index index.html /index.html;
    add_header Set-Cookie "x_vue_path=/$1;path=/;";
    # /Users/zhangpanqin/staic/+/$1/index.html 可以到每個(gè)項(xiàng)目下 index.html
    try_files $uri $uri/ /$1/index.html @404router;
  }
  # 查找靜態(tài)資源,也可以在這里添加緩存。
  location ~ (.css|js)$ {
    try_files $uri $cookie_x_vue_path/$uri @404router;
  }
  location @404router {
    return 404;
  }
}

下面這個(gè)是重定向的配置

server {
  listen 8087;
  root /Users/zhangpanqin/staic/;

  location ~ /(.*)/.*/? {
    index index.html /index.html;
    add_header Set-Cookie "x_vue_path=/$1;path=/;";
    try_files $uri $uri/ /$1/index.html @404router;
  }
  location ~ (.css|js)$ {
    # 匹配到 /app/index.css 的資源,直接訪問
    rewrite ^($cookie_x_vue_path)/.* $uri break;
    # 訪問的資源 /index.css 302 臨時(shí)重定向到 /app/index.css
    rewrite (.css|js)$ $cookie_x_vue_path$uri redirect;
  }
  location @404router {
    return 404;
  }
}

根據(jù)這個(gè)思路就可以把所有的資源進(jìn)行轉(zhuǎn)發(fā)了,不用改業(yè)務(wù)代碼,只需給 vue-router 加上一個(gè) base 基礎(chǔ)路由。

SpringBoot 部署 Vue 項(xiàng)目

Nginx 走通了,SpringBoot 依葫蘆畫瓢就行了,還是 java 寫的舒服,能 debug,哈哈。

SpringBoot 映射靜態(tài)資源

@Configuration
public class VueWebConfig implements WebMvcConfigurer {
  /**
   * 映射的靜態(tài)資源路徑
   * file:./static/ 路徑是相對(duì)于 user.dir 路徑,jar 包同級(jí)目錄下的 static
   */
  private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {"file:./static/", "classpath:/META-INF/resources/",
      "classpath:/resources/", "classpath:/static/", "classpath:/public/"};

  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    // 添加靜態(tài)資源緩存
    CacheControl cacheControl = CacheControl.maxAge(5, TimeUnit.HOURS).cachePublic();
    registry.addResourceHandler("/**").addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS).setCacheControl(cacheControl);
  }


  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    // 配置要攔截的資源,主要用于 添加 cookie 
    registry.addInterceptor(new VueCookieInterceptor()).addPathPatterns("/test/**");
  }

  // vue 路由轉(zhuǎn)發(fā)使用的,也做 接口請(qǐng)求找不到的
  @Bean
  public VueErrorController vueErrorController() {
    return new VueErrorController(new DefaultErrorAttributes());
  }
}

項(xiàng)目靜態(tài)資源路徑添加 cookie

public class VueCookieInterceptor implements HandlerInterceptor {
  public static final String VUE_HTML_COOKIE_NAME = "x_vue_path";

  public static final String VUE_HTML_COOKIE_VALUE = "/test";

  /**
   * 配置請(qǐng)求資源路徑 /test 下全部加上 cookie
   */
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    final Cookie cookieByName = getCookieByName(request, VUE_HTML_COOKIE_NAME);
    if (Objects.isNull(cookieByName)) {
      final Cookie cookie = new Cookie(VUE_HTML_COOKIE_NAME, VUE_HTML_COOKIE_VALUE);
      // 項(xiàng)目下的 url 都帶能帶上
      cookie.setPath("/");
      cookie.setHttpOnly(true);
      response.addCookie(cookie);
    }
    return true;
  }

  public static Cookie getCookieByName(HttpServletRequest httpServletRequest, String cookieName) {
    final Cookie[] cookies = httpServletRequest.getCookies();
    if (Objects.isNull(cookieName) || Objects.isNull(cookies)) {
      return null;
    }
    for (Cookie cookie : cookies) {
      final String name = cookie.getName();
      if (Objects.equals(cookieName, name)) {
        return cookie;
      }
    }
    return null;
  }
}

請(qǐng)求出現(xiàn)錯(cuò)誤做資源的轉(zhuǎn)發(fā)

訪問錯(cuò)誤的跳轉(zhuǎn)要分清楚 接口請(qǐng)求和靜態(tài)資源的請(qǐng)求,通過 accept 可以判斷。

@RequestMapping("/error")
public class VueErrorController extends AbstractErrorController {

  private static final String ONLINE_SAIL = VUE_HTML_COOKIE_NAME;

  private static final String ERROR_BEFORE_PATH = "javax.servlet.error.request_uri";

  public VueErrorController(DefaultErrorAttributes defaultErrorAttributes) {
    super(defaultErrorAttributes);
  }

  @Override
  public String getErrorPath() {
    return "/error";
  }

  @RequestMapping
  public ModelAndView errorHtml(HttpServletRequest httpServletRequest, HttpServletResponse response, @CookieValue(name = ONLINE_SAIL, required = false, defaultValue = "") String cookie) {
    final Object attribute = httpServletRequest.getAttribute(ERROR_BEFORE_PATH);
    if (cookie.length() > 0 && Objects.nonNull(attribute)) {
      response.setStatus(HttpStatus.OK.value());
      String requestURI = attribute.toString();
      // 訪問的路徑?jīng)]有以 vue 部署的路徑結(jié)尾,補(bǔ)充上路徑轉(zhuǎn)發(fā)去訪問
      if (!requestURI.startsWith(cookie)) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setStatus(HttpStatus.OK);
        // 靜態(tài)資源不想轉(zhuǎn)發(fā),重定向的話,修改為 redirect
        String viewName = "forward:" + cookie + requestURI;
        modelAndView.setViewName(viewName);
        return modelAndView;
      }
    }
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setStatus(HttpStatus.OK);
    modelAndView.setViewName("forward:/test/index.html");
    return modelAndView;
  }

  // 處理請(qǐng)求頭為 accept 為 application/json 的請(qǐng)求,就是接口請(qǐng)求返回json 數(shù)據(jù)
  @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
  public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
    HttpStatus status = getStatus(request);
    if (status == HttpStatus.NO_CONTENT) {
      return new ResponseEntity<>(status);
    }
    final Map<String, Object> errorAttributes = getErrorAttributes(request, true);
    return new ResponseEntity<>(errorAttributes, status);
  }

首頁(yè)跳轉(zhuǎn)

@Controller
public class IndexController {
  @RequestMapping(value = {"/test", "/test"})
  public String index() {
    return "forward:/test/index.html";
  }
}

本文由 張攀欽的博客 www.mflyyou.cn/ 創(chuàng)作。 可自由轉(zhuǎn)載、引用,但需署名作者且注明文章出處。

到此這篇關(guān)于你不知道的SpringBoot與Vue部署解決方案的文章就介紹到這了,更多相關(guān)SpringBoot與Vue部署內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用vue3+TS實(shí)現(xiàn)簡(jiǎn)易組件庫(kù)的全過程

    使用vue3+TS實(shí)現(xiàn)簡(jiǎn)易組件庫(kù)的全過程

    當(dāng)市面上主流的組件庫(kù)不能滿足我們業(yè)務(wù)需求的時(shí)候,那么我們就有必要開發(fā)一套屬于自己團(tuán)隊(duì)的組件庫(kù),下面這篇文章主要給大家介紹了如何使用vue3+TS實(shí)現(xiàn)簡(jiǎn)易組件庫(kù)的相關(guān)資料,需要的朋友可以參考下
    2022-03-03
  • Vue實(shí)現(xiàn)一個(gè)無限加載列表功能

    Vue實(shí)現(xiàn)一個(gè)無限加載列表功能

    這篇文章主要介紹了Vue實(shí)現(xiàn)一個(gè)無限加載列表功能,需要的朋友可以參考下
    2018-11-11
  • 利用vue實(shí)現(xiàn)打印頁(yè)面的幾種方法總結(jié)

    利用vue實(shí)現(xiàn)打印頁(yè)面的幾種方法總結(jié)

    在項(xiàng)目里有個(gè)打印功能,將頁(yè)面的部分內(nèi)容打印出來,所以下面這篇文章主要給大家介紹了關(guān)于利用vue實(shí)現(xiàn)打印頁(yè)面的幾種方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-11-11
  • Vue框架TypeScript裝飾器使用指南小結(jié)

    Vue框架TypeScript裝飾器使用指南小結(jié)

    這篇文章主要介紹了Vue框架TypeScript裝飾器使用指南小結(jié),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-02-02
  • Vue項(xiàng)目識(shí)別不到@別名問題及解決

    Vue項(xiàng)目識(shí)別不到@別名問題及解決

    這篇文章主要介紹了Vue項(xiàng)目識(shí)別不到@別名問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • Vue 使用超圖SuperMap的實(shí)踐

    Vue 使用超圖SuperMap的實(shí)踐

    作為一名剛?cè)腴T計(jì)算機(jī)語言的人來說,要想快速完成測(cè)試開發(fā)地圖項(xiàng)目,肯定要接用到SuperMap,本文主要介紹了Vue 使用超圖SuperMap的實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • element-ui自定義表格如何給input雙向綁定數(shù)據(jù)

    element-ui自定義表格如何給input雙向綁定數(shù)據(jù)

    這篇文章主要介紹了element-ui自定義表格如何給input雙向綁定數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • Vue報(bào)錯(cuò)"Failed?to?resolve?loader:less-loader"的解決方法

    Vue報(bào)錯(cuò)"Failed?to?resolve?loader:less-loader"的解決方

    這篇文章主要給大家介紹了關(guān)于Vue報(bào)錯(cuò)"Failed?to?resolve?loader:less-loader"的解決方法,文中通過圖文介紹的非常詳細(xì),對(duì)同樣遇到這樣問題的朋友具有一定的需要的朋友可以參考下
    2023-02-02
  • 在uniapp中實(shí)現(xiàn)圖形驗(yàn)證碼的詳細(xì)步驟

    在uniapp中實(shí)現(xiàn)圖形驗(yàn)證碼的詳細(xì)步驟

    圖形驗(yàn)證碼是一種常見的安全措施,用于防止自動(dòng)化軟件(機(jī)器人)濫用網(wǎng)站資源,如自動(dòng)提交表單,這篇文章主要介紹了在uniapp中實(shí)現(xiàn)圖形驗(yàn)證碼的詳細(xì)步驟,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-11-11
  • vue?tailwindcss安裝配置教程示例詳解

    vue?tailwindcss安裝配置教程示例詳解

    這篇文章主要為大家介紹了vue?tailwindcss安裝配置教程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09

最新評(píng)論

胶州市| 金沙县| 改则县| 九江市| 西贡区| 武平县| 宣恩县| 晋宁县| 丁青县| 扎囊县| 威远县| 静海县| 乌恰县| 饶平县| 成都市| 西峡县| 通江县| 松溪县| 长宁区| 昌江| 丹凤县| 阿图什市| 无极县| 龙陵县| 茶陵县| 宜春市| 高阳县| 邯郸县| 琼结县| 益阳市| 潜山县| 高邑县| 寻甸| 兴文县| 石首市| 瑞金市| 彰武县| 伽师县| 张家界市| 鞍山市| 金塔县|