12.6详解前后端对接
详解前后端对接
前端
先看前端,主要代码如下:
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,那么就不存在跨域问题了。