浏览器异常:TypeError 问题描述 封装好的request.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import axios from 'axios' export function request (config ) { const instance = axios.create ({ baseURL : 'http://127.0.0.1:8181' , timeout : 5000 }) instance.interceptors .request .use (config => { return config }, err => { console .log (err); }) instance.interceptors .response .use (res => { return res.data }, err => { console .log (err); }) return instance (config) }
axios发送请求代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import {request} from "@/network/request" ;export default { name : "Blogs" , data ( ) { return { currentPage : 1 , total : 0 , size : 4 , pages : 0 , blogs : [] } }, methods : { getBlogs (currentPage, size ) { request ({ url : '/getBlogs?currentPage=' + currentPage + '&size=' + size }).then (res => { this .total = res.data .data .total this .size = res.data .data .size this .pages = res.data .data .pages this .blogs = res.data .data .records }) }, },
解决思路
起初我以为是total这个属性读取不到,将this赋值给_this,在request里再使用 _this.total访问,还是报错;
于是去百度,看到别人报这个错是因为使用Vue.use(axios)
,改为原型全局注册后就不报错了:Vue.prototype.$http = axios
因为暂时想不出解决方法,所以我放弃使用封装的request.js,改用下面这种方法来使用axios:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import Vue from 'vue' import App from './App.vue' import router from './router' import store from './store' import axios from 'axios' Vue .prototype .$http = axiosaxios.defaults .baseURL = 'http://localhost:8181' axios.defaults .withCredentials = true Vue .config .productionTip = false new Vue ({ router, store, render : h => h (App ) }).$mount('#app' )
1 2 3 4 this .$http .get ('http://localhost:8181/blogs' ).then (res => { console .log (res) })
请求400 问题描述 后端:
前端:
1 2 3 4 5 6 7 8 9 10 11 12 13 data ( ) { return { ruleForm : { username : '' , password : '' , } }; }, methods : { submitForm (formName ) { this .$refs [formName].validate ((valid ) => { if (valid) { this .$http .post ('/login' , this .ruleForm ).then ((res ) => {
登录页面提交表单后:
解决方法
可以看到图中的Content-Type:application/json
如果前端传入的是json数据(Content-Type:application/json ),那么后端使用@RequestBody HashMap<String, String> map
或者@RequestBody User user
进行接收。
如果前端传入的是简单类型数据(Content-Type:application/x-www-form-urlencoded ),那么后端可以使用@RequestParam("id") String id
。
spring boot一些注解的详解
跨域与拦截器导致跨域失败 拦截器和跨域的配置代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package top.nanzx.blog.config;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import org.springframework.web.servlet.HandlerInterceptor;import top.nanzx.blog.entity.Admin;import top.nanzx.blog.service.AdminService;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;@Component public class AdminLoginInterceptor implements HandlerInterceptor { @Autowired AdminService adminService; @Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Cookie[] cookies = request.getCookies(); Admin admin = adminService.getOne(new QueryWrapper <Admin>().eq("id" , 1 )); String token = admin.getToken(); for (Cookie c : cookies) { if (c.getName().equals("token" )) { return token.equals(c.getValue()); } } return false ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package top.nanzx.blog.config;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.CorsRegistry;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration public class Config implements WebMvcConfigurer { @Autowired AdminLoginInterceptor adminLoginInterceptor; @Override public void addCorsMappings (CorsRegistry registry) { registry.addMapping("/**" ) .allowedOriginPatterns("*" ) .allowedMethods("GET" , "POST" , "HEAD" , "PUT" , "DELETE" , "OPTIONS" ) .allowCredentials(true ).allowedOrigins() .maxAge(3600 ) .allowedHeaders("*" ); } @Override public void addInterceptors (InterceptorRegistry registry) { registry.addInterceptor(adminLoginInterceptor).excludePathPatterns("/getBlogs" ,"/getBlog/*" ,"/login" ,"/getAdminMess" ); } }
产生问题
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求(preflight)。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。
预检请求用的请求方法是OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是Origin,表示请求来自哪个源。
在非简单请求的时候,总是报跨域访问的错误:
预检请求被拦截器拦截后,服务器端没有给浏览器返回必要的跨域指示信息,浏览器没收到指示信息就认为服务器不允许跨域请求,就会报错。
解决 拦截器截取到请求时先进行判断,如果是option请求的话,则放行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package top.nanzx.blog.config;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import org.springframework.web.servlet.HandlerInterceptor;import top.nanzx.blog.entity.Admin;import top.nanzx.blog.service.AdminService;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;@Component public class AdminLoginInterceptor implements HandlerInterceptor { @Autowired AdminService adminService; @Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if ("OPTIONS" .equals(request.getMethod().toUpperCase())) { System.err.println("OP:OK" ); return true ; } Cookie[] cookies = request.getCookies(); Admin admin = adminService.getOne(new QueryWrapper <Admin>().eq("id" , 1 )); String token = admin.getToken(); for (Cookie c : cookies) { if (c.getName().equals("token" )) { return token.equals(c.getValue()); } } return false ; } }
参考文章:跨域与拦截器导致跨域失败
response响应异常 1 java.lang.IllegalStateException: Cannot call sendError() after the response has been committed
下载文件接口如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @Override public JsonResult download (int courseId, String fileName, HttpServletResponse response) { Means means = meansDao.queryFile(fileName, courseId); File file = new File (means.getFilePath() +'\\' + means.getFileName()); if (!file.exists()) { return new JsonResult (1 , "文件不存在!" , null ); } response.setContentType("application/force-download" ); response.addHeader("Content-Disposition" , "attachment;fileName=" + new String (fileName.getBytes(StandardCharsets.UTF_8), Charset.forName("ISO8859-1" ))); byte [] buffer = new byte [1024 ]; try { FileInputStream fis = new FileInputStream (file); BufferedInputStream bis = new BufferedInputStream (fis); OutputStream os = response.getOutputStream(); int i = bis.read(buffer); while (i != -1 ) { os.write(buffer, 0 , i); i = bis.read(buffer); } fis.close(); } catch (Exception e) { e.printStackTrace(); return new JsonResult (1 , "文件下载失败。" , null ); } return new JsonResult (0 , "文件下载成功。" , null ); }
出现这个错误,应该是多次response导致的,可以这么理解,http server发送response后就关闭了socket,这个时候再次发送response给http client就会出现这个问题。 而我代码中传输完文件后,流一关闭,socket也就关闭了。
解决办法:如果下载出现问题,返回 JsonResult 让前台知道问题详情,下载成功的话,直接return null 就Ok了。
修改代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @Override public JsonResult download (int courseId, String fileName, HttpServletResponse response) { Means means = meansDao.queryFile(fileName, courseId); File file = new File (means.getFilePath() +'\\' + means.getFileName()); if (!file.exists()) { return new JsonResult (1 , "文件不存在!" , null ); } response.setContentType("application/force-download" ); response.addHeader("Content-Disposition" , "attachment;fileName=" + new String (fileName.getBytes(StandardCharsets.UTF_8), Charset.forName("ISO8859-1" ))); byte [] buffer = new byte [1024 ]; try { FileInputStream fis = new FileInputStream (file); BufferedInputStream bis = new BufferedInputStream (fis); OutputStream os = response.getOutputStream(); int i = bis.read(buffer); while (i != -1 ) { os.write(buffer, 0 , i); i = bis.read(buffer); } fis.close(); } catch (Exception e) { e.printStackTrace(); return new JsonResult (1 , "文件下载失败。" , null ); } return null ; }
前端Json数据解析异常 1 2 3 4 Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `java.lang.String` out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_ARRAY token at [Source: (PushbackInputStream); line: 1, column: 101] (through reference chain: java.util.HashMap["object"])]
出错原因:前端传值类型与后端接收值的类型不一致,无法解析
这是我前端传输的数据:
1 2 3 4 5 6 7 8 9 10 11 <script> export default { data() { return { ruleForm: { courseName: '', classes: [], }, } } }
这是我后端对应的接口:
1 2 3 4 @PostMapping("/createCourse") public JsonResult createCourse (@RequestBody HashMap<String, String> map) { return teacherService.createCourse(map); }
前端数组类型,后端无法用string类型接收。
解决方法:
1 2 3 4 5 6 7 8 9 10 11 12 前端=>后端: //格式化数组--转字符串 this.tag = this.tag.join(','); 后端=>前端: //格式化字符串--转数组 for(var i in data){ if(data[i].tag!==""){ data[i].tag = data[i].tag.split(','); } }
项目代码解决:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <script> export default { name: "AddCourse", data() { return { ruleForm: { courseName: '', classes: [], }, }; }, computed: { formData() { return { courseName: this.ruleForm.courseName, classes: this.ruleForm.classes.join(','), } } }, methods: { submitForm(formName) { this.$refs[formName].validate((valid) => { if (valid) { this.$http.post('/teacher/createCourse', this.formData).then((res) => { ... } </script>
String格式转JSON格式输出到文本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 class JsonTool { private final boolean isTab = false ; public String stringToJSON (String strJson) { int tabNum = 0 ; StringBuilder jsonFormat = new StringBuilder (); int length = strJson.length(); for (int i = 0 ; i < length; i++) { char c = strJson.charAt(i); if (c == '{' ) { tabNum++; jsonFormat.append(c).append("\n" ); jsonFormat.append(getSpaceOrTab(tabNum)); } else if (c == '}' ) { tabNum--; jsonFormat.append("\n" ); jsonFormat.append(getSpaceOrTab(tabNum)); jsonFormat.append(c); } else if (c == ',' ) { jsonFormat.append(c).append("\n" ); jsonFormat.append(getSpaceOrTab(tabNum)); } else if ((c == ':' && strJson.charAt(i - 1 ) == '"' && strJson.charAt(i + 1 ) == '"' ) || (c == ':' && strJson.charAt(i + 1 ) == '[' ) || (c == ':' && strJson.charAt(i + 1 ) == '{' ) || (c == ':' && Character.isDigit(strJson.charAt(i + 1 )) && strJson.charAt(i - 1 ) == '"' )) { jsonFormat.append(c); jsonFormat.append(" " ); } else if (c == '[' && strJson.charAt(i + 1 ) != ']' ) { tabNum++; jsonFormat.append(c).append("\n" ); jsonFormat.append(getSpaceOrTab(tabNum)); } else if (c == ']' && strJson.charAt(i - 1 ) == '"' ) { tabNum--; jsonFormat.append("\n" ); jsonFormat.append(getSpaceOrTab(tabNum)); jsonFormat.append(c); } else { jsonFormat.append(c); } } return jsonFormat.toString(); } public String getSpaceOrTab (int tabNum) { StringBuilder sbTab = new StringBuilder (); for (int i = 0 ; i < tabNum; i++) { if (isTab) { sbTab.append('\t' ); } else { sbTab.append(" " ); } } return sbTab.toString(); } }
将DTO保存到指定路径 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 public static boolean requestAndSave (String method, String url, Map<String, String> params, String filePath) { boolean flag = false ; ApiRequest apiRequest; try { apiRequest = request(method, url, params); } catch (Exception e) { e.printStackTrace(); return false ; } String[] urlStrings = url.split("/" ); String interfaceName = urlStrings[urlStrings.length - 1 ]; Date date = new Date (); SimpleDateFormat formatter = new SimpleDateFormat ("yyyyMMddHHmmss" ); String dataTime = formatter.format(date); filePath = filePath + "\\" + interfaceName + "-" + dataTime + ".json" ; FileOutputStream fileOutputStream; OutputStreamWriter outputStreamWriter; BufferedWriter bufferedWriter = null ; try { File file = new File (filePath); if (!file.getParentFile().exists()) { flag = file.getParentFile().mkdirs(); } if (file.exists()) { flag = file.delete(); } String ojString = JSONObject.toJSONString(apiRequest); JsonTool tool = new JsonTool (); String text = tool.stringToJSON(ojString); fileOutputStream = new FileOutputStream (file); outputStreamWriter = new OutputStreamWriter (fileOutputStream, CHARSET); bufferedWriter = new BufferedWriter (outputStreamWriter); bufferedWriter.write(text); } catch (Exception e) { flag = false ; e.printStackTrace(); } finally { if (bufferedWriter != null ) { try { bufferedWriter.flush(); bufferedWriter.close(); } catch (IOException e) { e.printStackTrace(); } } } return flag; }
从JSON文件中读取json并转换成DTO 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public static ApiRequest readFromJsonFile (String filePath) { ApiRequest apiRequest; File file = new File (filePath); if (!file.exists()) { return null ; } String jsonStr = null ; FileInputStream fis; BufferedInputStream bis = null ; try { fis = new FileInputStream (file); bis = new BufferedInputStream (fis); int ch; StringBuilder str = new StringBuilder (); while ((ch = bis.read()) != -1 ) { str.append((char ) ch); } jsonStr = str.toString(); } catch (IOException e) { e.printStackTrace(); } finally { if (bis != null ) { try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } } apiRequest = JSONArray.parseObject(jsonStr, ApiRequest.class); return apiRequest; }
将请求结果封装成指定DTO 1 2 3 4 5 6 7 8 9 10 11 12 13 public static <T> T getResultDto (String method, String url, Map<String, String> params, Class<T> clazz) { ApiRequest apiRequest; try { apiRequest = request(method, url, params); } catch (Exception e) { e.printStackTrace(); return null ; } Object result = apiRequest.getResult(); String jsonString = JSON.toJSONString(result); return JSONObject.parseObject(jsonString, clazz); }