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对象

但是会报如下错误

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,那么就不存在跨域问题了。

posted @ 2024-12-06 12:44  vast_joy  阅读(12)  评论(0编辑  收藏  举报