踩坑问题:
ajax进行接口请求,接口返回302 Found状态状态码,浏览器自动触发接口二次请求并返回200状态码但页面并未发起重定向。通过window.open()、window.loaction.href 等方法可以打开重定向后的页面。
什么是HTTP状态码?
是用以表示网页服务器HTTP响应状态的3位数字代码。它由RFC 2616规范定义,并得到RFC 2518、RFC 2817、RFC 2295、RFC 2774、RFC 4918等规范扩展。
开发中常见状态码有:
- 1xx(信息状态码):
- 2xx(成功状态码)
- 3xx(重定向状态码)
- 4xx(客户端错误状态码)
- 5xx(服务器错误状态码)
重定向状态码 :
- 301 Moved Permanently:请求的资源已经被永久移动到新的URL。
- 302 Found(之前为Moved Temporarily):请求的资源暂时被移动到新的URL。
- 304 Not Modified:客户端发送了一个条件请求,服务器判断资源未发生变化。
综上:302 Found状态码表明请求的资源被暂时的移动到了由
头部指定的 URL 上。浏览器会重定向到这个URL, 但是搜索引擎不会对该资源的链接进行更新Location
解决不了需求。
上述对http状态码 3xx 做了简单的叙述,那么聊一聊我开发时遇到的问题。这个问题是由老项目改造时遇到的,原项目是基于后端的JSP页面,需前后端分离的形式重构代码。原JSP页面的账户登陆是通过form表单的形式发起的,当登陆接口请求成功返回302状态码后页面自动重定向到 location 指定的URL上 ,而前后端分离后他们也想要同样的效果。
开始踩坑! 我们项目是Angular技术栈,Angular提供了HTTP服务,该服务对浏览器的XMLHttpRequest对象进行了封装,使得开发者可以以Ajax的方式来从服务器请求数据。通过多次请求测试,接口请求状态码302后只是多发起了一次请求而页面并不能跳转或刷新。而第二次接口请求时报错。
可以明显看出报错原因是CORS问题,那是不是解决OCRS就可以了?
那么恭喜🎉,猜错了。
OCRS问题是ajax的同源策略,在非同域下的数据限制了JavaScript(JS)调用和修改。即使没有同源问题在请求重定向 locatin接口返回200后页面也是不能够跳转和刷新的。下面从JSP请求和Ajax的请求方面对这个问题详细的说明讨论。
JSP不涉及302问题原因:
不妨先看看JSP是如何实现页面跳转的,首先JSP项目并不存在前端SPA架构单页应用框架中的路由,而页面跳转则是通过浏览器切换页面实现的,大概方法如下:
1、超链接(Hyperlinks): 使用HTML的超链接标签<a>
可以实现在页面之间切换。
<a href="anotherPage.jsp">跳转到另一个页面</a>
2、表单提交(Form Submission): 在JSP中,可以使用HTML表单来收集用户输入,并通过提交表单来跳转到新的页面。表单的action
属性指定了表单数据提交到的URL。
<form action="submit_form_url" method="post"></form>
3、服务器端重定向(Server-side Redirects): 在服务器端,可以使用JSP的response
对象来进行重定向。例如,在JSP页面中可以使用以下代码:
<% response.sendRedirect("targetPage.jsp"); %>
4、转发(Forwarding): 与重定向不同,转发是在服务器端将请求转发到另一个资源(可以是JSP、Servlet等)。在转发过程中,URL在浏览器地址栏中不会改变。
RequestDispatcher dispatcher = request.getRequestDispatcher("targetPage.jsp");
dispatcher.forward(request, response);
JSP页面跳转总结:
页面跳转不是由前端路由控制,而是由浏览器发起请求不同的地址。而form表单中的action和a标签的href都是触发的浏览器请求,到这里不难看出JSP应用实际没有发起过Ajax请求,而页面的请求都是通过浏览器触发的,不存在跨域问题。而浏览器接口请求时302状态码可以直接触发浏览器的更新。下面再看看Ajax请求
Ajax302状态跳转失败的原因:
1、请求区别:
Ajax: SPA架构单页应用框架请求基于Ajax,Ajax(Asynchronous JavaScript and XML)的核心是异步通信,它允许在不刷新整个页面的情况下更新页面的部分内容。通过Ajax,JavaScript可以异步地与服务器交换数据,并仅更新页面中需要更改的部分。
浏览器发起的请求: 浏览器发起的普通请求通常会导致整个页面的刷新。也就是说,当用户触发一个请求(如点击链接或提交表单)时,浏览器会加载并显示新的页面内容,这通常涉及页面整体的重新加载和渲染。
2、Ajax在接收状态码时不会触发页面行为
主要在于Ajax请求的性质和设计目标。
-
异步性质:Ajax(Asynchronous JavaScript and XML)的核心在于其异步性。它允许在不重新加载整个页面的情况下,与服务器进行数据交换并更新页面的部分内容。这种异步通信模式意味着浏览器在发送请求后不会等待其完成就继续执行其他脚本或渲染任务。因此,当收到302响应时,浏览器不会自动执行重定向,因为这会打破异步通信的初衷。
-
MLHttpRequest和Fetch API的设计:无论是使用XMLHttpRequest对象还是现代的Fetch API来发起Ajax请求,这些API都被设计为只处理响应数据本身,而不是自动处理HTTP状态码(如302)所触发的行为。这提供了更大的灵活性,允许开发者根据响应内容自定义处理逻辑,包括是否以及如何处理重定向。
-
安全性考虑:自动处理302重定向可能会引发安全问题。例如,恶意服务器可能利用这一点来诱导浏览器跳转到不安全的或恶意的网站。通过要求开发者显式处理重定向,可以增加一层额外的安全控制,防止此类自动跳转的发生。
-
前端架构的控制:在现代前端应用中,通常使用单页应用(SPA)架构,其中页面的导航和状态管理更多地依赖于前端逻辑而不是传统的全页刷新。自动处理302重定向可能会干扰这种架构的状态管理,导致不一致的用户体验。因此,将重定向的控制权交给前端代码,可以确保应用的行为更加可预测和可控。
Ajax请求总结:
Ajax设计初衷异步处理服务器数据,实现页面数据替换而不是重新加载整个页面。而浏览器在监听到Ajax请求时302状态码会自动触发浏览器行为发起对返回接口location的请求,而ajax的异步处理机制的原因浏览器不会自动执行重定向。
我也试图通过状态码拦截的形式手动来处理location中的地址,但并未实现。浏览器302状态行为是在Ajax请求获取回调前触发的,最终解决办法是后端改为200状态码,重定向行为前端处理。
尾声:
感谢您的阅读,本人知识有限,文章潦草。诚求各路大佬及时指出本文中问题点或者描述不准确的地方。