12.6詳解前後端對接

vast_joy發表於2024-12-06

詳解前後端對接

前端

先看前端,主要程式碼如下:

LoginPage.vue

<template>
  <div>
    <form action="/user/login" method="POST" id="login-form">
      <input
        v-model="usernameInput"
        type="text"
        id="username"
        name="username"
        required
        placeholder="請輸入使用者名稱"
      />
      <input
        v-model="passwordInput"
        type="text"
        id="password"
        name="password"
        required
        placeholder="請輸入密碼"
      />
    </form>
  </div>
  <br />
  <div>
    <button :onclick="onSubmit">登入</button>
  </div>
</template>

<style scoped></style>

<script setup lang="ts">
import MyAxios from "@/plugins/myAxios";
import { ref } from "vue";

const usernameInput = ref("");
const passwordInput = ref("");

const onSubmit = async () => {
  const res = await MyAxios.post("/user/login", {
    username: usernameInput.value,
    password: passwordInput.value,
  });
  console.log(res);
};
</script>

myAxios.ts

import axios, {AxiosInstance} from "axios";

const myAxios: AxiosInstance = axios.create({
    baseURL: 'http://localhost:8080/api' ,
});

myAxios.defaults.withCredentials = true; // 配置為true

myAxios.interceptors.request.use(function (config) {
    console.log('我要發請求啦', config)
    return config;
}, function (error) {
    return Promise.reject(error);
});

myAxios.interceptors.response.use(function (response) {
    return response.data;
}, function (error) {
    return Promise.reject(error);
});

export default myAxios;

這裡我們主要注意這麼幾點

id="username"表示這個input標籤的唯一標識,在js中可以用

const username= document.getElementById('username')

來獲取username這個DOM物件

但是會報如下錯誤

image-20241205190247039

image-20241205190643929

原因是我們getElementById取的是DOM物件,我們要把他轉為HTMLInputElement然後用.value方法取到表單中使用者填入的值

const usernameInput= document.getElementById('username') as HTMLInputElement
const passwordInput= document.getElementById('password') as HTMLInputElement

const onSubmit= async () => {
  const res=await MyAxios.post('/user/login',{
    username: usernameInput.value,
    password: passwordInput.value,
  })
  console.log(res)
}

這樣寫,又會報如下的錯

image-20241205191233664

原因我們可以看chatgpt給出的解釋

1. 元素沒有被正確渲染

  • 你的程式碼可能在元件渲染之前就嘗試訪問 DOM 元素。這會導致 document.getElementById 找不到這些元素,從而返回 null

解決辦法: 使用 Vue 的 ref 代替 getElementById,這樣你可以確保元素在 Vue 渲染完畢之後才能訪問。

2. 使用 ref 引用 DOM 元素

在 Vue 中,使用 ref 來獲取 DOM 元素是更可靠的方式。透過 ref 你可以確保元素已經渲染並且能夠訪問它們。

說明我們想在.vue檔案中獲取表單的值,還得用響應式程式設計,用v-model雙向繫結動態獲取值,光用html和ts中的方法會報各種奇怪的錯誤。

所以還是老老實實有v-model

這裡再說一下<button :onclick="onSubmit">登入</button> —— 動態繫結事件

  • :onclick 是 Vue.js 中的事件繫結語法(v-on:click 的縮寫)。它允許你將事件繫結到元件方法或資料中。
  • 動態繫結:當你使用 :onclick="onSubmit" 時,onclick 事件會繫結到 Vue 例項中 onSubmit 方法。Vue 會在事件觸發時呼叫這個方法。
  • 響應式:Vue 會自動處理事件的繫結,並且當 onSubmit 方法的邏輯發生變化時,檢視會自動更新。

注意前端使用axios來發請求

後端

@RequestMapping("/login")
public R<User> userLogin(@RequestBody UserLoginRequest request, HttpServletRequest httpServletRequest){
    String username=request.getUsername();
    String password=request.getPassword();
    List<User> list;
    list=userMapper.GetUser(username);
    if (list.size()==0) return R.fail("使用者不存在");
    User resultUser=list.get(0);
    String TruePassword=list.get(0).getPassword();
    if (password.equals(TruePassword)) {
        System.out.println(resultUser);
        httpServletRequest.getSession().setAttribute(USER_LOGIN_STATE,resultUser);
        return R.ok("登入成功",resultUser);
    }
    log.info("查詢不到使用者,username={},password={}",username,password);
    return R.fail("使用者名稱或密碼錯誤");
}

注意這裡我們用R模板返回類,如果R最好要實現Serializable介面

並且使用postman測試帶有@RequestBody的介面時,要這樣測試

image-20241206111444097

原因是@RequestBody代表傳入的引數應該是一個JSON物件。不這麼測會報406 error

跨域問題

跨域問題的根源是瀏覽器為了保護使用者設定的同源策略

怎麼繞過呢?

本地開發環境

在userController上面加上註解

@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")

注意這裡的origins和allowCredentials都不要設為空,還是會報錯的

這樣設定完就解決了跨域問題,前端再次發請求,成功了

image-20241206114840168

生產環境

使用Nginx反向代理,原理瀏覽器只阻止網站直接請求和響應的傳遞,但是我們可以從原網站把請求發給一個nginx代理伺服器,再由nginx發給目標網站

同源策略只是瀏覽器的一個安全策略,只適用於瀏覽器向伺服器傳送請求的時候,當伺服器跟伺服器傳送請求的時候,自然就沒有這麼一層限制,只要是介面,就會返回。

就比如說,我們在localhost:3000埠開了前端介面,然後開一個nginx代理在localhost:8080埠的後端程式,那麼前端請求8080埠介面,會由nginx攔截轉發給8080,那麼就不存在跨域問題了。

相關文章