詳解前後端對接
前端
先看前端,主要程式碼如下:
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物件
但是會報如下錯誤
原因是我們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)
}
這樣寫,又會報如下的錯
原因我們可以看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的介面時,要這樣測試
原因是@RequestBody代表傳入的引數應該是一個JSON物件。不這麼測會報406 error
跨域問題
跨域問題的根源是瀏覽器為了保護使用者設定的同源策略
怎麼繞過呢?
本地開發環境
在userController上面加上註解
@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
注意這裡的origins和allowCredentials都不要設為空,還是會報錯的
這樣設定完就解決了跨域問題,前端再次發請求,成功了
生產環境
使用Nginx反向代理,原理瀏覽器只阻止網站直接請求和響應的傳遞,但是我們可以從原網站把請求發給一個nginx代理伺服器,再由nginx發給目標網站
同源策略只是瀏覽器的一個安全策略,只適用於瀏覽器向伺服器傳送請求的時候,當伺服器跟伺服器傳送請求的時候,自然就沒有這麼一層限制,只要是介面,就會返回。
就比如說,我們在localhost:3000埠開了前端介面,然後開一個nginx代理在localhost:8080埠的後端程式,那麼前端請求8080埠介面,會由nginx攔截轉發給8080,那麼就不存在跨域問題了。