文章编号:11167时间:2024-09-30人气:
在开发和调试 Web 应用程序时,能够轻松地打印出当前 URL 和查询参数非常有帮助。这有助于跟踪应用程序的状态并隔离问题。
在 JavaScript 中,我们可以使用
location.href
属性来获取当前 URL。
// 获取当前 URL
const url = location.href;// 输出当前 URL
console.log(`当前 URL:${url}`);
我们可以使用
location.search
属性来获取查询参数。
// 获取查询参数
const searchParams = location.search;// 输出查询参数
console.log(`查询参数:${searchParams}`);
利用这些特性,我们可以在 Web 应用程序中创建简单的调试工具。
下面,我们利用
location.href
和
localStorage
来创建一个简单的歌曲收藏应用。
// 创建一个歌曲收藏
const songs = [];// 将歌曲添加到收藏
function addSong(song) {songs.push(song);localStorage.setItem('songs', JSON.stringify(songs));
}// 从收藏中删除歌曲
function removeSong(song) {const index = songs.indexOf(song);if (index > -1) {songs.splice(index, 1);localStorage.setItem('songs', JSON.stringify(songs));}
}// 获取歌曲收藏
function getSongs() {const storedSongs = localStorage.getItem('songs');if (storedSongs) {return JSON.parse(storedSongs);} else {return [];}
}// 打印当前 URL 和歌曲收藏
function debug() {console.log(`当前 URL:${location.href}`);console.log(`歌曲收藏:${JSON.stringify(getSongs())}`);
}
我们可以通过以下方式使用这个应用:
1. 添加歌曲到收藏:调用
addSong
函数。
2. 从收藏中删除歌曲:调用
removeSong
函数。
3. 获取歌曲收藏:调用
getSongs
函数。
4. 调试:调用
debug
函数以输出当前 URL 和歌曲收藏。
通过使用
location.href
和
localStorage
,我们创建了一个简单的工具,可以帮助我们调试应用程序并跟踪其状态。
应该熟练掌握的基础技能:
在 B/S 系统中,登录功能通常都是基于 Cookie 来实现的。 当用户登录成功后,一般会将登录状态记录到 Session 中,或者是给用户签发一个 Token,无论哪一种方式,都需要在客户端保存一些信息(Session ID 或 Token ),并要求客户端在之后的每次请求中携带它们。 在这样的场景下,使用 Cookie 无疑是最方便的,因此我们一般都会将 Session 的 ID 或 Token 保存到 Cookie 中,当服务端收到请求后,通过验证 Cookie 中的信息来判断用户是否登录 。
单点登录(Single Sign On, SSO)是指在同一帐号平台下的多个应用系统中,用户只需登录一次,即可访问所有相互信任的应用系统。 举例来说,网络贴吧和网络地图是网络公司旗下的两个不同的应用系统,如果用户在网络贴吧登录过之后,当他访问网络地图时无需再次登录,那么就说明网络贴吧和网络地图之间实现了单点登录。
单点登录的本质就是在多个应用系统中共享登录状态。 如果用户的登录状态是记录在 Session 中的,要实现共享登录状态,就要先共享 Session,比如可以将 Session 序列化到 Redis 中,让多个应用系统共享同一个 Redis,直接读取 Redis 来获取 Session。
当然仅此是不够的,因为不同的应用系统有着不同的域名,尽管 Session 共享了,但是由于 Session ID 是往往保存在浏览器 Cookie 中的,因此存在作用域的限制,无法跨域名传递,也就是说当用户在 中登录后,Session ID 仅在浏览器访问 时才会自动在请求头中携带,而当浏览器访问 时,Session ID 是不会被带过去的。 实现单点登录的关键在于,如何让 Session ID(或 Token)在多个域中共享。
实现方式一:父域 Cookie
在将具体实现之前,我们先来聊一聊 Cookie 的作用域。
Cookie 的作用域由 domain 属性和 path 属性共同决定。 domain 属性的有效值为当前域或其父域的域名/IP地址,在 Tomcat 中,domain 属性默认为当前域的域名/IP地址。 path 属性的有效值是以“/”开头的路径,在 Tomcat 中,path 属性默认为当前 Web 应用的上下文路径。
如果将 Cookie 的 domain 属性设置为当前域的父域,那么就认为它是父域 Cookie。 Cookie 有一个特点,即父域中的 Cookie 被子域所共享,换言之,子域会自动继承父域中的Cookie。
利用 Cookie 的这个特点,不难想到,将 Session ID(或 Token)保存到父域中不就行了。 没错,我们只需要将 Cookie 的 domain 属性设置为父域的域名(主域名),同时将 Cookie 的 path 属性设置为根路径,这样所有的子域应用就都可以访问到这个 Cookie 了。 不过这要求应用系统的域名需建立在一个共同的主域名之下,如 和 ,它们都建立在 这个主域名之下,那么它们就可以通过这种方式来实现单点登录。
总结:此种实现方式比较简单,但不支持跨主域名。
实现方式二:认证中心
我们可以部署一个认证中心,认证中心就是一个专门负责处理登录请求的独立的 Web 服务。
用户统一在认证中心进行登录,登录成功后,认证中心记录用户的登录状态,并将 Token 写入 Cookie。 (注意这个 Cookie 是认证中心的,应用系统是访问不到的。 )
应用系统检查当前请求有没有 Token,如果没有,说明用户在当前系统中尚未登录,那么就将页面跳转至认证中心。 由于这个操作会将认证中心的 Cookie 自动带过去,因此,认证中心能够根据 Cookie 知道用户是否已经登录过了。 如果认证中心发现用户尚未登录,则返回登录页面,等待用户登录,如果发现用户已经登录过了,就不会让用户再次登录了,而是会跳转回目标 URL ,并在跳转前生成一个 Token,拼接在目标 URL 的后面,回传给目标应用系统。
应用系统拿到 Token 之后,还需要向认证中心确认下 Token 的合法性,防止用户伪造。 确认无误后,应用系统记录用户的登录状态,并将 Token 写入 Cookie,然后给本次访问放行。 (注意这个 Cookie 是当前应用系统的,其他应用系统是访问不到的。 )当用户再次访问当前应用系统时,就会自动带上这个 Token,应用系统验证 Token 发现用户已登录,于是就不会有认证中心什么事了。
这里顺便介绍两款认证中心的开源实现:
Apereo CAS 是一个企业级单点登录系统,其中 CAS 的意思是”Central Authentication Service“。 它最初是耶鲁大学实验室的项目,后来转让给了 JASIG 组织,项目更名为 JASIG CAS,后来该组织并入了Apereo 基金会,项目也随之更名为 Apereo CAS。
XXL-SSO 是一个简易的单点登录系统,由大众点评工程师许雪里个人开发,代码比较简单,没有做安全控制,因而不推荐直接应用在项目中,这里列出来仅供参考。
总结:此种实现方式相对复杂,支持跨域,扩展性好,是单点登录的标准做法。
实现方式三:LocalStorage 跨域
前面,我们说实现单点登录的关键在于,如何让 Session ID(或 Token)在多个域中共享。
父域 Cookie 确实是一种不错的解决方案,但是不支持跨域。那么有没有什么奇淫技巧能够让 Cookie 跨域传递呢?
很遗憾,浏览器对 Cookie 的跨域限制越来越严格。 Chrome 浏览器还给 Cookie 新增了一个 SameSite 属性,此举几乎禁止了一切跨域请求的 Cookie 传递(超链接除外),并且只有当使用 HTTPs 协议时,才有可能被允许在 AJAX 跨域请求中接受服务器传来的 Cookie。
不过,在前后端分离的情况下,完全可以不使用 Cookie,我们可以选择将 Session ID (或 Token )保存到浏览器的 LocalStorage 中,让前端在每次向后端发送请求时,主动将 LocalStorage 的数据传递给服务端。 这些都是由前端来控制的,后端需要做的仅仅是在用户登录成功后,将 Session ID (或 Token )放在响应体中传递给前端。
在这样的场景下,单点登录完全可以在前端实现。 前端拿到 Session ID (或 Token )后,除了将它写入自己的 LocalStorage 中之外,还可以通过特殊手段将它写入多个其他域下的 LocalStorage 中。
原文链接:前端通过 iframe+postMessage() 方式,将同一份 Token 写入到了多个域下的 LocalStorage 中,前端每次在向后端发送请求之前,都会主动从 LocalStorage 中读取 Token 并在请求中携带,这样就实现了同一份 Token 被多个域所共享。
总结:此种实现方式完全由前端控制,几乎不需要后端参与,同样支持跨域。
补充:域名分级
从专业的角度来说(根据《计算机网络》中的定义),、 为一级域名(也称顶级域名),、 为二级域名,、 为三级域名,以此类推,N 级域名就是 N-1 级域名的直接子域名。
从使用者的角度来说,一般把可支持独立备案的主域名称作一级域名,如 、 皆可称作一级域名,在主域名下建立的直接子域名称作二级域名,如 为二级域名。
需求最近遇到个需求:前端登录后,后端返回token和token有效时间,当token过期时要求用旧token去获取新的token,前端需要做到无痛刷新token,即请求刷新token时要做到用户无感知。 需求解析当用户发起一个请求时,判断token是否已过期,若已过期则先调refreshToken接口,拿到新的token后再继续执行之前的请求。 这个问题的难点在于:当同时发起多个请求,而刷新token的接口还没返回,此时其他请求该如何处理?接下来会循序渐进地分享一下整个过程。 实现思路由于后端返回了token的有效时间,可以有两种方法:方法一:在请求发起前拦截每个请求,判断token的有效时间是否已经过期,若已过期,则将请求挂起,先刷新token后再继续请求。 方法二:不在请求前拦截,而是拦截返回后的数据。 先发起请求,接口返回过期后,先刷新token,再进行一次重试。 两种方法对比方法一 优点: 在请求前拦截,能节省请求,省流量。 缺点: 需要后端额外提供一个token过期时间的字段;使用了本地时间判断,若本地时间被篡改,特别是本地时间比服务器时间慢时,拦截会失败。 PS:token有效时间建议是时间段,类似缓存的MaxAge,而不要是绝对时间。 当服务器和本地时间不一致时,绝对时间会有问题。 方法二优点:不需额外的token过期字段,不需判断时间。 缺点: 会消耗多一次请求,耗流量。 综上,方法一和二优缺点是互补的,方法一有校验失败的风险(本地时间被篡改时,当然一般没有用户闲的蛋疼去改本地时间的啦),方法二更简单粗暴,等知道服务器已经过期了再重试一次,只是会耗多一个请求。 在这里博主选择了 方法二。 实现这里会使用axios来实现,方法一是请求前拦截,所以会使用()这个方法;而方法二是请求后拦截,所以会使用()方法。 封装axios基本骨架首先说明一下,项目中的token是存在localStorage中的。 基本骨架:import axios from axios// 从localStorage中获取tokenfunction getLocalToken () { const token = (token) return token}// 给实例添加一个setToken方法,用于登录后将最新token动态添加到header,同时将token保存在localStorage中 = (token) => { [X-Token] = token (token, token)}// 创建一个axios实例const instance = ({ baseURL: /api, timeout: , headers: { Content-Type: application/json, X-Token: getLocalToken() // headers塞token }})// 拦截返回的数据(response => { // 接下来会在这里进行token过期的逻辑处理 return response}, error => { return (error)})export default instance这个是项目中一般的axios实例的封装,创建实例时,将本地已有的token放进header,然后export出去供调用。 接下来就是如何拦截返回的数据啦。 拦截实现后端接口一般会有一个约定好的数据结构,如:{code: 1234, message: token过期, data: {}}如我这里,后端约定当code === 1234时表示token过期了,此时就要求刷新token。 (response => { const { code } = if (code === 1234) { // 说明token过期了,刷新token return refreshToken()(res => { // 刷新token成功,将最新的token更新到header中,同时保存在localStorage中 const { token } = (token) // 获取当前失败的请求 const config = // 重置一下配置 [X-Token] = token = // url已经带上了/api,避免出现/api/api的情况 // 重试当前请求并返回promise return instance(config) })(res => { (refreshtoken error =>, res) //刷新token失败,神仙也救不了了,跳转到首页重新登录吧 = / }) } return response}, error => { return (error)})function refreshToken () { // instance是当前中已创建的axios实例 return (/refreshtoken)(res => )}这里需要额外注意的是,就是原请求的配置,但这个是已经处理过了的,已经带上了baseUrl,因此重试时需要去掉,同时token也是旧的,需要刷新下。 以上就基本做到了无痛刷新token,当token正常时,正常返回,当token已过期,则axios内部进行一次刷新token和重试。 对调用者来说,axios内部的刷新token是一个黑盒,是无感知的,因此需求已经做到了。 问题和优化上面的代码还是存在一些问题的,没有考虑到多次请求的问题,因此需要进一步优化。 如何防止多次刷新token如果refreshToken接口还没返回,此时再有一个过期的请求进来,上面的代码就会再一次执行refreshToken,这就会导致多次执行刷新token的接口,因此需要防止这个问题。 我们可以在中用一个flag来标记当前是否正在刷新token的状态,如果正在刷新则不再调用刷新token的接口。 // 是否正在刷新的标记let isRefreshing = (response => { const { code } = if (code === 1234) { if (!isRefreshing) { isRefreshing = true return refreshToken()(res => { const { token } = (token) const config = [X-Token] = token = return instance(config) })(res => { (refreshtoken error =>, res) = / })(() => { isRefreshing = false }) } } return response}, error => { return (error)})这样子就可以避免在刷新token时再进入方法了。 但是这种做法是相当于把其他失败的接口给舍弃了,假如同时发起两个请求,且几乎同时返回,第一个请求肯定是进入了refreshToken后再重试,而第二个请求则被丢弃了,仍是返回失败,所以接下来还得解决其他接口的重试问题。 同时发起两个或以上的请求时,其他接口如何重试两个接口几乎同时发起和返回,第一个接口会进入刷新token后重试的流程,而第二个接口需要先存起来,然后等刷新token后再重试。 同样,如果同时发起三个请求,此时需要缓存后两个接口,等刷新token后再重试。 由于接口都是异步的,处理起来会有点麻烦。 当第二个过期的请求进来,token正在刷新,我们先将这个请求存到一个数组队列中,想办法让这个请求处于等待中,一直等到刷新token后再逐个重试清空请求队列。 那么如何做到让这个请求处于等待中呢?为了解决这个问题,我们得借助Promise。 将请求存进队列中后,同时返回一个Promise,让这个Promise一直处于Pending状态(即不调用resolve),此时这个请求就会一直等啊等,只要我们不执行resolve,这个请求就会一直在等待。 当刷新请求的接口返回来后,我们再调用resolve,逐个重试。 最终代码:// 是否正在刷新的标记let isRefreshing = false// 重试队列,每一项将是一个待执行的函数形式const requests = [](response => { const { code } = if (code === 1234) { const config = if (!isRefreshing) { isRefreshing = true return refreshToken()(res => { const { token } = (token) [X-Token] = token = // 已经刷新了token,将所有队列中的请求进行重试 (cb => cb(token)) return instance(config) })(res => { (refreshtoken error =>, res) = / })(() => { isRefreshing = false }) } else { // 正在刷新token,返回一个未执行resolve的promise return new Promise((resolve) => { // 将resolve放进队列,用一个函数形式来保存,等token刷新后直接执行 ((token) => { = [X-Token] = token resolve(instance(config)) }) }) } } return response}, error => { return (error)})这里可能比较难理解的是requests这个队列中保存的是一个函数,这是为了让resolve不执行,先存起来,等刷新token后更方便调用这个函数使得resolve执行。 至此,问题应该都解决了。 最后完整代码import axios from axios// 从localStorage中获取tokenfunction getLocalToken () { const token = (token) return token}// 给实例添加一个setToken方法,用于登录后将最新token动态添加到header,同时将token保存在localStorage中 = (token) => { [X-Token] = token (token, token)}function refreshToken () { // instance是当前中已创建的axios实例 return (/refreshtoken)(res => )}// 创建一个axios实例const instance = ({ baseURL: /api, timeout: , headers: { Content-Type: application/json, X-Token: getLocalToken() // headers塞token }})// 是否正在刷新的标记let isRefreshing = false// 重试队列,每一项将是一个待执行的函数形式const requests = [](response => { const { code } = if (code === 1234) { const config = if (!isRefreshing) { isRefreshing = true return refreshToken()(res => { const { token } = (token) [X-Token] = token = // 已经刷新了token,将所有队列中的请求进行重试 (cb => cb(token)) return instance(config) })(res => { (refreshtoken error =>, res) = / })(() => { isRefreshing = false }) } else { // 正在刷新token,将返回一个未执行resolve的promise return new Promise((resolve) => { // 将resolve放进队列,用一个函数形式来保存,等token刷新后直接执行 ((token) => { = [X-Token] = token resolve(instance(config)) }) }) } } return response}, error => { return (error)})export default instance
浏览器出于安全方面的考虑,只允许客户端与本域(同协议、同域名、同端口,三者缺一不可)下的接口交互。 不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源,这被称为同源策略。
而有时候,我们不得不在一个客户端下访问不同域中的资源,于是需要用到一些方法来避开浏览器的同源策略,这些方法被称为跨域。
实现跨域有如下几种方法:
JSONP(JSONwithPadding)是数据格式JSON的一种使用模式,可以使网页实现跨域请求。 其原理主要利用了HTML的script标签。 由于script是采用开放策略,通过设置src引入不同域下的资源,所以可以通过script实现跨域,该方法需要后端支持。 jsonp跨域的实现步骤如下:
下面来做个演示,首先为演示方便,将系统的hosts做如下修改:
以上例子最终实现了由到的跨域。 应注意的是,因为script只能发送GET请求,所以jsonp只能实现GET请求的跨域。 如果希望能实现其他请求的跨域,就可以用接下来介绍的一种方法——CORS。
CORS(全称为:Cross-OriginResouceSharing)跨域资源共享,是一种通过ajax跨域请求资源的方法。 浏览器将CORS请求分为两大类,简单请求(simplerequest)和非简单请求(not-so-simplerequest,浏览器对这两种请求的处理方式不一样。 如果请求满足以下两个条件,则为简单请求。
简单请求的实现方式即当用XMLHttpRequest发请求时,浏览器如果发现该请求不符合同源策略,会给该请求加上一个请求头origin,origin用来说明本次请求来自哪个源(协议+域名+端口)。 如果origin指定的源不在后台允许范围内,后台会返回一个正常的HTTP响应,然后浏览器会发现该响应头部信息不包含Access-Control-Allow-Origin字段,然后抛出一个错误,该错误被XMLHttpRequest的onerror函数捕获,响应被驳回,但因为该错误无法通过状态码识别,所以HTTP回应的状态码还是200。 如果origin在后台允许范围内,则服务器返回的响应,会包含Access-Control-Allow-Origin:Origin(指定的源)信息,浏览器此时不会抛错,响应能正常处理。
非简单请求是是请求方法为PUT或DELETE,又或者Content-Type为application/json的对服务器有特殊要求的请求。 非简单请求的CORS请求,会在正式通信前增加一次HTTP查询,称为预检(preflight),询问服务器当前网页所在域名是否在服务器的许可名单中,如果在,则发出正式的XMLHttpRequest,之后就与简单请求一样,不在则报错。
依旧用上面的例子。
最终实现的效果与第一个jsonp的例子一样。
还有一种方式,就是通过降域来实现跨域。 即通过设置的方式,将两个域名的domain设置为一个,如对于和,可以通过js设置=,实现跨域。
做个演示,假设在下有一个文件,其中中有一个iframe,它的src为。
用降域方法实现跨域操作简单,但是有一些缺点。 比如域名只能往下设置,不能回去,比如从回到。 同时如果一个子域名被攻击,多个被降域的域名都会被连带攻击,有很大的安全风险。
postMessage是一个webAPI,可以实现跨域通信。 ()被调用时,会在所有页面脚本执行完毕后,向目标窗口派发一个MessageEvent消息。 语法如下:
MessageEvent具有如下属性:
用一个与上面降域类似的例子来做演示。 同样有两个页面和,中的iframe的src指向。
最终实现与通信效果如下:
使用postMessage方法应注意的是,如果不希望从其他网站接收message,那么不要为message事件添加任何监听器。 如果确实希望接收其他网站的message,那么应该始终使用origin和source属性来验证发件人的身份,以免被恶意的网站攻击。
以上就是几种常见的跨域方法,各有优劣,且各自都有一定的安全问题,在日常应用中,需要有针对性的使用,对可能的安全风险采取相应措施。
前后端联调——跨域问题
前端通过http请求跨域的同时需要带上cookie信息,前端需要设置withCredentials=true。
而后端也需要有所修改。
Access-Control-Allow-Origin字段必须指定域名,不能为*
Access-Control-Allow-Credentials为true
后端可以通过HtttpServletRequest的Header中找到Origin。 是跨域地址的host加port。
后端需要维护一个跨域URL的白名单,用Origincontains匹配白名单的URL,成功则配置response的Access-Control-Allow-Origin,指定Origin。
就实现跨域传cookie了。
参考:
什么是跨域、怎么解决跨域?一个请求url的**协议、端口、域名**其中任意一个与当前页面url不相同就是跨域
即:?(http/https)协议、(segmentfault)主域名、(www)子域名、(8080)端口
是因为浏览器的同源策略的限制,同源策略是一种安全策略,同源指的是域名,协议,端口相同,会阻止一个域的js脚本和另一个域的内容进行交互。 防止在一个浏览器中的两个页面产生不安全、异常的行为。
当然如果不同源的话会产生一定的限制:
【1】无法读取非同源网页的Cookie、LocalStorage和IndexedDB
【2】无法接触非同源网页的DOM
【3】无法向非同源地址发送AJAX请求
(‘script’)生成一个script标签,然后插body里而已。
JSONP的实现原理就是创建一个script标签,再把需要请求的api地址放到src里.这个请求只能用GET方法,不可能是POST(向服务端传送数据)。
一种非正式传输协议,它会允许用户传递一个callback参数给服务端,然后服务端返回数据的时候会将这个callback参数作为函数名来包裹住JSON数据,然后客户端就可以随意的定义自己的函数来处理返回的数据了。
一般是后端在处理请求数据的时候,添加允许跨域的请求头信息,服务端设置Access-Control-Allow-Origin就可以,如果需要携带cookie,前后端都需要设置
window对象有个name的属性,在一个window下,窗口载入的页面都是共享一个。
在中,怎么把页面加载进来,获取的数据。 在页面使用iframe,可以去获取的数据,然后在页面中取得iframe获取得数据。
但是iframe想要获取中的数据,只需要给这个iframe的src设为就可以,如果想要得到iframe所获得的数据,也就是iframe的的值,还要把这个iframe的src设成跟页面同一个域才可以,不然访问不到iframe里的属性。
//父窗口打开一个子窗口
??varopenWindow=(,title);
//父窗口向子窗口发消息(第一个参数代表发送的内容,第二个参数代表接收消息窗口的url)
??(Nicetomeetyou!,);
调用message事件,监听对方发送的消息
//监听message消息
??(message,function(e){
??();//发送消息的窗口
??();//消息发向的网址
??();?//?发送的消息
??},false);
??#监听9099端口
??listen9099;
??#域名是localhost
??server_namelocalhost;
??#凡是localhost:9099/api这个样子的,都转发到真正的服务端地址
??location^~/api{
????proxy_pass;
//请求的时候直接用回前端这边的域名,这就不会跨域,然后Nginx监听到凡是localhost:9099/api这个样子的,都转发到真正的服务端地址
?method:POST,
?headers:{
??Accept:application/json,
??Content-Type:application/json
??msg:HelloIframePost
关于跨域的问题一、在前端开发过程中,如果准备开发富应用,跨域的问题将会随之而来。
????????我们先看看什么是跨域呢:
????????所谓跨域,或者异源,是指主机名(域名)、协议、端口号只要有其一不同,就为不同的域(或源)。 出于保护用户数据的目的,浏览器有一个最基本的策略就是同源策略,只允许页面内的脚本访问当前域的资源(加载脚本、资源等不受此限制)。
二、如果浏览器厂商不对跨域请求进行处理,会给我们带来什么危害呢?
????有心人士(病毒制造者)会利用这个漏洞进行如下攻击:
????/XSRF攻击,简单的来讲就是在页面中请求的接口(浏览器会自动带上用户在的cookie),从而获取用户的在的相关信息。
????注入攻击,类似于SQL攻击,提交含有恶意脚本的数据到服务器,从而达到破坏页面或者获取用户的cookie。
三、我们了解到了什么是跨域,那我们又应该如何解决呢,现在找到了这些比较权威的文章,大家先品读一下:
????????官方网站关于跨域的文章(CrossOrigin),HTTP访问控制(CORS)
????????官方网站关于浏览器同源策略的简要介绍(SameOrigin),?浏览器的同源策略
四、读完这些文章,你打算怎么处理跨域问题呢,我先谈谈自己关于跨域的解决方案:
????????1.采用CORS协议,直接在Nginx中设置允许跨域的header(也可以在后端的应用程序内设置,不过在Nginx入口配置的话更加统一),在location配置中直接使用指令add_header(官方文档链接),示例配置如下:
????????2.使用JSONP,也是需要后端配合,利用“浏览器加载脚本、资源时不受同源策略的约束”这个特性,但是这种方式非常受限制,例如只能使用GET请求,不能携带自定义header等。
????3.其他的一些方法,例如,以及HTML5中的特性等
五、其他参考链接
????1.?浅谈JS跨域问题
????2.跨域资源共享CORS详解----阮一峰
六、声明
????现在网络上的知识非常复杂,有些是摘自权威书籍的,有些是作者自己理解然后记录下来的,有些是瞎掰的,所以一定要结合情况多多甄别,对于有权威文档的知识点,建议先参考文档。
后端配置跨域原文连接:原文地址
跨域的详细介绍可以参考:浏览器和服务器实现跨域(CORS)判定的原理,这里不多赘述。
1、主要就是客户端向发送了服务端请求,服务器已经能返回数据,但是浏览器不接收
2、在接口里面加上:(因为request是处理请求,response是返回结果)
(Access-Control-Allow-Origin,?*);
(Cache-Control,no-cache);?
3、如果是使用SpringBoot创建的项目,直接添加一句注解到controller和方法就可以了:
@CrossOrigin
其中@CrossOrigin中的2个参数:
origins?:允许可访问的域列表
maxAge:准备响应前的缓存持续的最大时间(以秒为单位)。
在这个例子中,对于retrieve()和remove()处理方法都启用了跨域支持,还可以看到如何使用@CrossOrigin属性定制CORS配置。 如果同时使用controller和方法级别的CORS配置,Spring将合并两个注释属性以创建合并的CORS配置。
4、如果您正在使用SpringSecurity,请确保在Spring安全级别启用CORS,并允许它利用SpringMVC级别定义的配置。
二、全局CORS配置
除了细粒度、基于注释的配置之外,您还可能需要定义一些全局CORS配置。 这类似于使用筛选器,但可以声明为SpringMVC并结合细粒度@CrossOrigin配置。 默认情况下,所有originsandGET,HEADandPOSTmethods是允许的。
JavaConfig
使整个应用程序的CORS简化为:
更多使用请看原文连接和官方文档
后端解决前端跨域请求问题场景:前后端分离,页面和后端项目部署在不同服务器,出现请求跨域问题。
原因:CORS:跨来源资源共享(CORS)是一份浏览器技术的规范,提供了Web服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略,是JSONP模式的现代版。 与JSONP不同,CORS除了GET要求方法以外也支持其他的HTTP要求。 用CORS可以让网页设计师用一般的XMLHttpRequest,这种方式的错误处理比JSONP要来的好,JSONP对于RESTful的API来说,发送POST/PUT/DELET请求将成为问题,不利于接口的统一。 但另一方面,JSONP可以在不支持CORS的老旧浏览器上运作。 不过现代的浏览器(IE10以上)基本都支持CORS。
预检请求(option):在CORS中,可以使用OPTIONS方法发起一个预检请求(一般都是浏览检测到请求跨域时,会自动发起),以检测实际请求是否可以被服务器所接受。 预检请求报文中的Access-Control-Request-Method首部字段告知服务器实际请求所使用的HTTP方法;Access-Control-Request-Headers首部字段告知服务器实际请求所携带的自定义首部字段。 服务器基于从预检请求获得的信息来判断,是否接受接下来的实际请求。
解决方案:
1、创建一个过滤器,过滤options请求。
*解决跨域问题
publicclassCorsFilterimplementsFilter{//filter接口的自定义实现
??publicvoidinit(FilterConfigfilterConfig)throwsServletException{
??publicvoiddoFilter(ServletRequestservletRequest,ServletResponseservletResponse,FilterChainfilterChain)throwsIOException,ServletException{
HttpServletResponseresponse=(HttpServletResponse)servletResponse;
????HttpServletRequestrequest=(HttpServletRequest)servletRequest;
????(Access-Control-Allow-Origin,*);
????if((())){//这里通过判断请求的方法,判断此次是否是预检请求,如果是,立即返回一个204状态吗,标示,允许跨域;预检后,正式请求,这个方法参数就是我们设置的post了
??????(_NO_CONTENT);//_NO_CONTENT=204
??????(Access-Control-Allow-Methods,POST,GET,DELETE,OPTIONS,DELETE);//当判定为预检请求后,设定允许请求的方法
??????(Access-Control-Allow-Headers,Content-Type,x-requested-with);//当判定为预检请求后,设定允许请求的头部类型
??????(Access-Control-Max-Age,1);?//预检有效保持时间
(request,response);
??publicvoiddestroy(){
2、修改文件
?filter-namecors/filter-name
?/filter-class
filter-mapping
filter-namecors/filter-name
?url-pattern/*?/url-pattern
/filter-mapping
3、添加HttpRequestHandlerAdapter?http请求处理器适配器。
HttpRequestHandlerAdapter作为HTTP请求处理器适配器仅仅支持对HTTP请求处理器的适配。 它简单的将HTTP请求对象和响应对象传递给HTTP请求处理器的实现,它并不需要返回值。 它主要应用在基于HTTP的远程调用的实现上。
beanclass=/
1、用js的href函数来实现。 代码参考:引用script语句=需要跳转到的页面跳转到指定页面定义和用法href属性是一个可读可写的字符串,可设置或返回当前显示的文档的完整URL。
2、测试用返回引用的函数值作为赋值表达式的左值。
3、弄一个名字为网页跳转的简单静态网页,网页内有一张图片,图片要置于网如果您在此页面内跳转,则可以使用代码跳转到指定位置。 转到指定位置是指向idweizhi的页面部分的超链接。 位置是需要转移的部分。
4、由上可知,可以通过setHeader来实现某页面停留若干秒后,自动重定向到另一页面。
又是该死的js,怎么跳转到指定tab页1、html有一个用js控制的选项卡0003;当点击html中的2链接到html时显示选项卡02的内容。
2、键盘tab键的键代码是9,可以用来获得按下一个键时的键代码,进而可以知道按下了哪个键。 接着程序找出当前光标所在的文本框,然后将光标移到它的前一个文本框中。
3、--将些链接加入到你想跳转到的位置-#后面的skip你可以自己定义与下面的那个中的对应就可以了!就能实习到指定的位置了。
4、方法如下:首先,选中整个表格,然后点击右键,选择菜单中的“表格属性”,这样会弹出对话框。 在对话框中,切换到“行”选项卡,如下图。
5、http:///uid--id-html看下这文章。
JS实现页面跳转的几种方式[1]在页面的head内加入meta标签实现[2]js代码实现setTimeout((0),1000)javascript中的跳转方法=(-1);//参数是负几,就后退几次。
这样就能实现,参数不丢失了。 主要就是页码和筛选条件。 纯js页面跳转要传复杂数据不好做,要用localStorage,这个东东在各浏览器中是不一样的。
您好,你这样用JS实现页面跳转是会使整个页面都跳转,如果你正在看视频,点击下一页,又要重新加载,这是不符合规范的哦。 网上那些是用的分页控件,还有一个方法是利用Ajax做。
那你别用js跳转了,直接用标准html跳转,这个兼容性最高。
这是典型的分页,你这个布局是有点问题的。 分页的页是动态创建出来的。 HTML:直接一个DIV就行,是分页的容器!下面是一个分页的例子的代码。 我建议你还是网上找一套关于JavaScript分页的视频来看,看完自然就懂了。
内容声明:
1、本站收录的内容来源于大数据收集,版权归原网站所有!
2、本站收录的内容若侵害到您的利益,请联系我们进行删除处理!
3、本站不接受违法信息,如您发现违法内容,请联系我们进行举报处理!
4、本文地址:http://www.jujiwang.com/article/2aaae25f80b34ac7dacf.html,复制请保留版权链接!
在社交媒体时代,短视频已经成为传播信息、吸引流量的重要方式,想要在朋友圈中脱颖而出,一款优秀的短视频神器必不可少,本文将为你介绍几款刷爆朋友圈的短视频神器,以及一些刷爆朋友圈文案的技巧,刷爆朋友圈的短视频神器1.剪映剪映是一款功能强大的短视频编辑软件,操作简单,功能丰富,它提供了丰富的特效、转场、贴纸和音乐素材,可以满足各种短视频创作...。
最新资讯 2024-10-01 17:51:02
图表对于可视化数据非常重要,但创建图表可能很费时且具有挑战性,这就是为什么使用免费的图表制作工具和JavaScript图表库来简化流程至关重要的原因,免费的图表制作工具GoogleCharts,Google提供的一套全面的图表制作工具,提供各种图表类型,它易于使用,可与GoogleSheets和GoogleDataStudio等其他G...。
最新资讯 2024-10-01 12:42:59
引言在软件开发领域,心血漏洞是一种严重的漏洞,它允许攻击者获得对计算机系统的未经授权的访问,这些漏洞可能对个人、企业和整个行业产生毁灭性的影响,本文旨在阐明心血漏洞的潜在危险,并提供最佳实践以减轻其风险,什么是心血漏洞,心血漏洞是由软件中的缺陷或编码错误造成的,它允许攻击者利用该缺陷访问计算机系统,这些漏洞通常可以被远程利用,这意味着...。
最新资讯 2024-09-25 21:28:50
简介Ant,ApacheAnt,是一种基于Java的构建工具,用于自动化构建流程,包括编译、测试、打包和部署,Ant.jar包是Ant的核心库,它提供了构建过程的大量功能,通过使用Ant.jar,开发人员可以创建自定义构建脚本,使构建流程更有效、更可重复,Ant.jar的作用Ant.jar提供了许多功能,包括,任务,Ant.jar包含...。
最新资讯 2024-09-16 11:34:21
前言对于初学者来说,掌握C语言的基础语法和概念是至关重要的,如果你想要提升自己的C语言技能,达到二级水平,那么你需要深入了解语言的更高级特性,本文将指导你踏上C语言进阶之路,帮助你掌握二级C语言技能,提升你的编程能力,二级C语言技能简介二级C语言技能涵盖了以下主题,指针和动态内存管理结构体和联合文件处理预处理器和宏位操作数据结构指针和...。
互联网资讯 2024-09-11 10:31:05
Javaweb是什么JavaWeb是一个用于开发服务器端应用程序的框架,它使用Java语言和各种库和框架来创建动态Web页面、处理用户请求并生成HTML响应,Javaweb是前端还是后端JavaWeb主要用于后端开发,即处理服务器端的逻辑和数据处理,它与前端技术,如HTML、CSS和JavaScript,配合使用,用于构建用户界面和处...。
技术教程 2024-09-11 08:18:15
在数据分析中,拟合函数是一种强大的工具,可以帮助我们探索数据趋势和模式,通过将数学方程拟合到数据点,我们可以揭示数据的潜在结构,并对未来趋势进行预测,什么是拟合函数,拟合函数是一种数学方程,它以最合适的方式近似给定数据集,拟合函数通过最小化数据点和函数之间误差的总和来确定,这种误差通常用均方误差,MSE,来衡量,拟合函数的常用类型包括...。
本站公告 2024-09-10 11:05:52
前言中国作为全球数字化大国,对于开发者而言是一个充满机遇的沃土,为了助力中国开发者茁壮成长,本文汇集了丰富的资源和支持,旨在为他们的职业发展提供全方位的赋能,教育与培训在线课程平台网易云课堂,提供海量免费和付费课程,涵盖从基础编程到高级技术,Coursera,与世界名校合作,提供计算机科学、数据科学和AI等领域的认证课程,Udemy,...。
互联网资讯 2024-09-09 10:03:16
PDO,PHPDataObjects,是PHP中的一个扩展,它提供了一个统一的接口来访问不同的数据库管理系统,DBMS,这意味着你可以使用相同的代码与MySQL、PostgreSQL和SQLServer等不同的数据库交互,PDO优势使用PDO有一些优势,包括,统一的接口,PDO提供了一个统一的接口,用于与不同的数据库交互,简化了与不...。
本站公告 2024-09-07 23:31:54
Java中的视频编码和解码,优化视频传输介绍在当今数字世界中,视频已成为至关重要的一部分,从流媒体服务到视频会议,视频无处不在,为了在互联网上有效地传输视频,需要对其进行编码和解码,Java中的视频编码视频编码是将未压缩视频数据转换为压缩视频格式的过程,这可以通过使用编解码器,编解码器,来实现,它是一种执行编码和解码操作的软件或硬件组...。
本站公告 2024-09-07 21:49:20
在机器学习中,数据是至关重要的,它为算法提供学习和做出预测所需的信息,数据通常是混乱和无序的,这使得机器学习算法很难从中提取有用的模式,因此,随机性在机器学习中起着至关重要的作用,Random函数就是其中的一个关键工具,什么是Random函数,Random函数是一个用于生成伪随机数的计算机函数,虽然这些数字实际上并非完全随机,但它们看...。
技术教程 2024-09-07 02:47:17
如何使用photoshop制作网页很多朋友不知道用ps制作网页的规范,下面介绍一下,01打开电脑中的Photoshop界面,首先,我们创建一个画布,宽度为1200,任意高度,分辨率为72,02画布创建完成后,我们在1200px左右两边拉一条辅助线固定,03然后打开画布大小,取消,相对,,宽度调整为1920px,04设置好之后,在红色区...。
技术教程 2024-09-02 00:56:33