后端解决前端跨域请求问题
场景:前后端分离,页面和后端项目部署在不同服务器,出现请求跨域问题。
原因: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请求。
package com.biz.eisp.sci.util;
import org.apache.commons.httpclient.HttpStatus;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 解决跨域问题
*
*/
public class CorsFilterimplements Filter {//filter 接口的自定义实现
public void init(FilterConfig filterConfig)throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
response.setHeader(\"Access-Control-Allow-Origin\", \"*\");
if (\"OPTIONS\".equals(request.getMethod())){//这里通过判断请求的方法,判断此次是否是预检请求,如果是,立即返回一个204状态吗,标示,允许跨域;预检后,正式请求,这个方法参数就是我们设置的post了
response.setStatus(HttpStatus.SC_NO_CONTENT); //HttpStatus.SC_NO_CONTENT = 204
response.setHeader(\"Access-Control-Allow-Methods\", \"POST, GET, DELETE, OPTIONS, DELETE\");//当判定为预检请求后,设定允许请求的方法
response.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type, x-requested-with\"); //当判定为预检请求后,设定允许请求的头部类型
response.addHeader(\"Access-Control-Max-Age\", \"1\"); // 预检有效保持时间
}
filterChain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
2、修改web.xml文件
filter
filter-namecors/filter-name
filter-classcom.biz.eisp.sci.util.CorsFilter/filter-class
/filter
filter-mapping
filter-namecors/filter-name
url-pattern/* /url-pattern
/filter-mapping
3、spring-mvc.xml添加HttpRequestHandlerAdapter http请求处理器适配器。
HttpRequestHandlerAdapter作为HTTP请求处理器适配器仅仅支持对HTTP请求处理器的适配。它简单的将HTTP请求对象和响应对象传递给HTTP请求处理器的实现,它并不需要返回值。它主要应用在基于HTTP的远程调用的实现上。
bean class=\"org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter\"/
跨域怎么解决
问题一:如何解决跨域问题 特别注意两点:
第一,如果是协议和端口造成的跨域问题“前台”是无能为力的,
第二:在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。
“URL的首部”指window.location.protocol +window.location.host,也可以理解为“Domains, protocols and ports must match”。
2. 前端解决跨域问题
1 document.domain + iframe (只有在主域相同的时候才能使用该方法)
1) 在a/a中:
复制代码
document.domain = \'a\';
var ifr = document.createElement(\'iframe\');
ifr.src = \'script.a/b\';
ifr.display = none;
document.body.appendChild(ifr);
ifr.onload = function(){
var doc = ifr.contentDocument || ifr.contentWindow.document;
在这里操作doc,也就是b
ifr.onload = null;
};
复制代码
2) 在script.a/b中:
document.domain = \'a\';
2 动态创建script
这个没什么好说的,因为script标签不受同源策略的限制。
复制代码
function loadScript(url, func) {
var head = document.head || document.getElementByTagName(\'head\')[0];
var script = document.createElement(\'script\');
script.src = url;
script.onload = script.onreadystatechange = function(){
if(!this.readyState || this.readyState==\'loaded\' || this.readyState==\'plete\'){
func();
script.onload = script.onreadystatechange = null;
}
};
head.insertBefore(script......
问题二:如何解决跨域问题 由 于此前很少写前端的代码(哈哈,不合格的程序员啊),最近项目中用到json作为系统间交互的手段,自然就伴随着众多ajax请求,随之而来的就是要解决 ajax的跨域问题。本篇将讲述一个小白从遇到跨域不知道是跨域问题,到知道是跨域问题不知道如何解决,再到解决跨域问题,最后找到两种方法解决ajax 跨域问题的全过程。
不知是跨域问题
起 因是这样的,为了复用,减少重复开发,单独开发了一个用户权限管理系统,共其他系统获取认证与授权信息,暂且称之为A系统;调用A系统以B为例。在B系统 中用ajax调用A系统系统的接口(数据格式为json),当时特别困惑,在A系统中访问相应的url可正常回返json数据,但是在B系统中使用 ajax请求同样的url则一点儿反应都没有,好像什么都没有发生一样。这样反反复复改来改去好久都没能解决,于是求救同事,提醒可能是ajax跨域问 题,于是就将这个问题当做跨域问题来解决了。
知跨域而不知如何解决
知道问题的确切原因,剩下的就是找到解决问题的方法了。google了好久,再次在同事的指点下知道jQuery的ajax有jsonp这样的属性可以用来解决跨域的问题。
找到一种解决方式
现在也知道了怎样来解决跨域问题,余下的就是实现的细节了。实现的过程中错误还是避免不了的。由于不了解json和jsonp两种格式的区别,也犯了错误,google了好久才解决。
首先来看看在页面中如何使用jQuery的ajax解决跨域问题的简单版:
复制代码
$(document).ready(function(){
var url=\'localhost:8080/...upById
+?id=1callback=?\';
$.ajax({
url:url,
dataType:\'jsonp\',
processData: false,
type:\'get\',
success:function(data){
alert(data.name);
},
error:function(XMLHttpRequest, textStatus, errorThrown) {
alert(XMLHttpRequest.status);
alert(XMLHttpRequest.readyState);
alert(textStatus);
}});
});
复制代码
这样写是完全没有问题的,起先error的处理函数中仅仅是alert(“error”),为了进一步弄清楚是什么原因造成了错误,故将处理函数变 为上面的实现方式。最后一行alert使用为;parsererror。百思不得其解,继续google,最终还是在万能的stackoverflow找 到了答案,链接在这里。原因是jsonp的格式与json格式有着细微的差别,所以在server端的代码上稍稍有所不同。
比较一下json与jsonp格式的区别:
json格式:
{
messageq......
问题三:跨域是指什么,因为什么引起的?有哪些解决方案?web前端知识 跨域是指 不同域名之间相互访问 例如 我的电脑上有2个服务器 192.168.0.11 192.168.0.12 如果第一个服务器上的页面要访问第二个服务器 就叫做跨域 或者baidu 要访问xxx 也是不同域名 也是跨域
HTML5 里有个window.postMessage 方法,支持跨域访问,详情可以参考
webhek/window-postmessage-api
如果你的程序在服务器上,也可以进行相应的操作来完成跨域访问
纯手打 有问题欢迎咨询
问题四:如何解决跨域问题 打开IE浏览器,在工具菜单下选择Internet选项,打开Internet选项卡
切换到安全选项卡下,点击可信站点,然后单击站点按钮
可信站点窗口输入网址到可信站点的区域,点击添加按钮,网址则会添加到网站列表下,最后关闭可信站点窗口
还是在安全选项卡下的可信站点,点击自定义级别
打开受信任的站点区域窗口,找到跨域浏览窗口和框架选择启用
在当前窗口中继续往下翻,通过域访问数据源也选择启用,点击确定关闭受信任的站点区域窗口
在Internet窗口也点击确定按钮,同时关闭浏览器
在请求的js脚本中添加是否允许跨域访问的权限,jQuery.support.cors默认值为true,则代表允许;反之,不允许。设置完成,重新打开浏览器验证即可
问题五:$跨域请求怎么解决 post请求进行跨域
angularjs内置封装了类ajax的网络服务$,所以实现了依赖外部插件来完成完整的前后端分离方案
$scope.main = {
getData: function () {
$({
method: \'POST\',
url: \'localhost:8000\',
headers: {
\'Content-Type\' : \'application/x--form-urlencoded\'
},
data: {
myUrl: \'c.m.163/...0\'
}
}).then(function success(result) {
数据请求成功
console.log(result.data);
},function error(err) {
数据请求失败
console.log(err);
});
}
};
注意:表面上是向$中传入了一个回调函数提供相应时调用,实际是返回了一个promise对象,angular1.2以上的版本对$进行了优化
优化后:
$scope.main = {
getData: function () {
var myUrl = \'c.m.163/...0\';
var url = \'localhost:8000\';
var promise = $({
method: \'POST\',
url: url,
headers: {
\'Content-Type\' : \'text/plain\'
......
问题六:如何解决跨域问题 关于跨域名问题还是问题么,这方面的解决实践非常多,今天我就旧话重提把我所知道的通过几个应用场景来分别总结一下(转帖请注明出处:blog.csdn/lenel)
先说明一点:我说的某某域名在您的控制下的意思是这个域名下的网页由您来负责开发内部的JavaScript
场景一:将bbs.xxx的页面用iframe嵌入到xxx的中,如何在iframe内外使用js通信(转帖请注明出处:blog.csdn/lenel)
一级域名都是xxx 这个域名一定是在您的控制下,所以你只要在两个页面中同时升级域名即可
在父窗口和iframe内部分别加上js语句:document.domain=xxx;
之后2个页面就等于在同一域名下,通过window.parent oIframe.contentDocument就可以相互访问,进行无障碍的JS通信
在新浪、淘宝等很多页面都能找到这样的语句。不过document.domain不可以随便指定,只能向上升级,从bbs.xxx升级到yyy肯定会出错
场景二:将yyy的页面用iframe嵌入到xxx的中,两个域名都在您的控制下,如何在iframe内外进行一定的数据交流(转帖请注明出处:blog.csdn/lenel)
你可以通过相互改变hash值的方式来进行一些数据的通信
这里的实现基于如下技术要点:
1、父窗口通过改变子窗口的src中的hash值把一部分信息传入,如果src只有hash部分改变,那么子窗口是不会重新载入的。
2、
子窗口可以重写父窗口的location.href,但是注意这里子窗口无法读取而只能重写location.href所以要求前提是您控制两个域名,知
道当前父窗口的location.href是什么并写在子窗口内,这样通过parent.location.href =
已知的父窗口的href+#+hash。这样父窗口只有hash改变也不会重载。
3、上面两步分别做到了两个窗口之间的无刷新数据通知,
那么下面的来说如何感知数据变化。标准中没有相关规定,所以当前的任意浏览器遇到location.hash变化都不会触发任何javaScript事
......
问题七:如何解决javascript的跨域问题 一般是用iframe设置
document.domain = \'a\';var ifr = document.createElement(\'iframe\');ifr.src = \'a/index\';ifr.style.display = \'none\';document.body.appendChild(ifr);ifr.onload = function(){ var doc = ifr.contentDocument || ifr.contentWindow.document; console.log(doc.documentElement.innetHTML);};然后HTML5新特性有 ,postMessage
function Init () { if (window.addEventListener) { all browsers except IE before version 9 window.addEventListener (message, OnMessage, false); } else { if (window.attachEvent) { IE before version 9 window.attachEvent(onmessage, OnMessage); } } } function GetState () { var frame = document.getElementById (myFrame); var message = getstate;参数if (frame.contentWindow.postMessage) { 传递的参数,后面是传递的你的跨域域名frame.contentWindow.postMessage (message, *); } } function OnMessage (event) { console.log(event.data);} document.body.onload=function(){Init();GetState();};
问题八:如何解决跨域问题 VPN或者域名
问题九:如何解决请求跨域的问题 jsonp 是写 script 标签,只能满足 get 请求。跨域 post 的话,IE8 及以上和其他主流浏览器可以用 window.postMessage 来实现,也就是传说中的 HTML5 方法了,可以看下标准,代码很简单。IE6、7 就用老式的方法
问题十:怎么解决服务器间的跨域问题 服务端的解决方案的基本原理就是,由客户端将请求发给本域服务器,再由本域服务器的代理来请求数据并将响应返回给客户端。
最常用的服务器解决方案就是利用web服务器本身提供的proxy功能,如apache和ligd的mod_proxy模块。在百度内 部,tran *** it的分流功能也可以解决部分跨域问题。但这些方法都有一定的局限性,鉴于安全性等问题的考虑,space这边最后开发了一个专门用于处
理跨域请求代理服务的spproxy模块,用于彻底解决js跨域问题。
下面我们将以空间的开放平台为例,简单介绍下如何通过apache的mod_proxy、tran *** it的分流以及space的spproxy模块来解
决该跨域问题,并简单介绍下spproxy的一些特性、缺点及下一步的改进计划。
空间在展现每个UWA开放模块之前都必须请求该模块的xml源代码以进行解析,每个模块的源代码文件都是存放在act域下的/ow/uwa目录下,那么在
用户空间首页(hi域)中请求该xml文件时就会存在js跨域问题。要解决该问题,只能让js向hi域的web服务器请求xml文件,而hi域web服务
器则通过一定的代理机制(如mod_proxy、tran *** it分流、spproxy)向act域的web服务器请求文件
怎么解决服务器间的跨域问题
关于跨域名问题还是问题么,这方面的解决实践非常多,今天我就旧话重提把我所知道的通过几个应用场景来分别总结一下(转帖请注明出处:)
先说明一点:我说的某某域名在您的控制下的意思是这个域名下的网页由您来负责开发内部的JavaScript
场景一:将bbs.xxx.com的页面用iframe嵌入到的中,如何在iframe内外使用js通信(转帖请注明出处:)
一级域名都是xxx.com 这个域名一定是在您的控制下,所以你只要在两个页面中同时升级域名即可
在父窗口和iframe内部分别加上js语句:document.domain=\"xxx.com\";
之后2个页面就等于在同一域名下,通过window.parent oIframe.contentDocument就可以相互访问,进行无障碍的JS通信
在新浪、淘宝等很多页面都能找到这样的语句。不过document.domain不可以随便指定,只能向上升级,从bbs.xxx.com升级到yyy.com肯定会出错
场景二:将的页面用iframe嵌入到的中,两个域名都在您的控制下,如何在iframe内外进行一定的数据交流(转帖请注明出处:)
你可以通过相互改变hash值的方式来进行一些数据的通信
这里的实现基于如下技术要点:
1、父窗口通过改变子窗口的src中的hash值把一部分信息传入,如果src只有hash部分改变,那么子窗口是不会重新载入的。
2、子窗口可以重写父窗口的location.href,但是注意这里子窗口无法读取而只能重写location.href所以要求前提是您控制两个域
名,知道当前父窗口的location.href是什么并写在子窗口内,这样通过parent.location.href =
\"已知的父窗口的href\" \"#\" hash。这样父窗口只有hash改变也不会重载。
3、上面两步分别做到了两个窗口之间的无刷新数据通知,那么下面的来说如何感知数据变化。标准中没有相关规定,所以当前的任意浏览器遇到
location.hash变化都不会触发任何javaScript事件,也就是说您要自己写监听函数来监视loaction.hash的值的变化。做法
是通过setTimeout或者setInterval来写一个监听函数每20-100ms查看一下hash是否变化,如果变化了驱动js根据新的数据做
想做的事情。
这种实现的一些分析:
1、信息通道是双向的,当然会兼容单向,如果只是父窗口向子窗口通知数据,只需要子窗口写hash监听,反之亦然。
2、局限性也是颇大,因为这种通信的前提是双方知道对方的location.href。如果父窗口带有动态的location.search也就是查询参数,那么子窗口的处理上就比较困难,需要把父窗口的location.search作为传递信息的一部分告知子窗口。
3、另外的困扰会有浏览器带给你,IE之外的浏览器遇到hash的改变会记录历史,这样你在处理前进后退的时候会非常头疼
场景三:将的页面用iframe嵌入到的中,只有被嵌入的yyy.com在您的控制下,如何在iframe内外进行一定的交流
真实场景:google adsence的一个需求,你希望google发现您的页面不能匹配出相关性非常好的按点击付费广告时,你希望google的广告iframe能够隐藏。
google的广告iframe在google域下显然不能把自己隐藏掉,那么怎么办呢?
1、google会提供给你一个html页面
2、您将这个页面放置在您的域名下,并告诉google它的位置
3、当google发现没有很好的广告时,会将子窗口的loaction重定向到您的那个页面下,这样您的页面因为同域名就可以访问父页面来隐藏自己了
是不是很巧的方法?
场景四:您是内容发布商,如何改造接口,让其他域名下的页面可以从浏览器端出发获得您的数据
我们知道ajax的xmlHttpRequest()说到底是一个无刷新请求服务器数据的辅助工具,但是xmlHttpRequest并不能跨域名请求数据,在某些情况下成了极大的限制。
但是我们如果通过其他方式完成无刷新请求数据不也可以么,我们用Dom方法操作动态JS脚本请求来做这件事。
//创建一个脚本节点
var oScript = document.createElement(\'script\');
//指定脚本src src可以指向任意域名
//注意src不再指向静态js,而是带着查询参数指向一个动态脚本广播服务。
oScript.src = \"?\" yourQueryString;
//如果指定了charset 同时还可以解决xmlHttpRequest另一大困扰 乱码问题
//oScript.charset = \"utf-8\";
//通过Dom操作把这个新的节点加入到文档当中
document.getElementsByTagName(\"head\")[0].appendChild(oScript);
这样只要query.php的输出是可执行的javaScript脚本,比如:djsCallBack({jsondata});
当他从服务器返回后就会自动执行,你可以方便的用json方式来做数据传递了。
要注意,您的脚本请求最好带上时间戳,避免浏览器缓存造成取回数据实时性下降。
如果您是数据提供者,您可以要求数据索取者在查询参数中提供回调函数名,比如query.php?callback=myDataHandler
跨域远程调试
为了使用远程调试,运行 Visual Studio 以及运行 msvsmon.exe 的用户身份非常重要。若要连接到 msvsmon,您必须使用与 msvsmon 相同的用户帐户或管理员帐户来运行 Visual Studio。(也可以将 msvsmon 配置为接受来自其他用户的连接。)如果运行 msvsmon 的用户可在 Visual Studio 计算机上通过身份验证,则 Visual Studio 将接受来自 msvsmon 的连接。 (该用户在 Visual Studio 计算机上必须有本地帐户。)在满足这些限制后,远程调试可应用于多种场合,包括:无双向信任的两个域。一个工作组中的两台计算机。工作组中的一台计算机和域中的另一台计算机。以本地帐户运行远程调试监视器 (msvsmon)或 Visual Studio。因此,您在每台计算机上都必须有一个本地用户帐户,并且两个帐户必须有相同的用户名和密码。如果想要使用不同的用户帐户运行 msvsmon 和Visual Studio,您在每台计算机中必须有两个用户帐户。如果某个域帐户与某个本地帐户拥有相同的名称和密码,则可以使用该域帐户运行 Visual Studio。在每台计算机中,仍须有拥有相同用户名和密码的本地帐户。对于工作组中安装了 Windows XP Professional 的计算机,本地安全设置可能会导致无法进行远程调试。为了能执行远程调试,必须将策略设置为“经典”。(此问题不适用于加入域的 Windows XP 计算机,也不适用于运行 Windows Server 2003 或较新版本的 Windows Server、Windows Vista 或 Windows 7 的计算机。)更改安全策略以允许在域之间进行远程调试 (Windows XP Professional)在本地计算机上,从“开始”菜单中选择“控制面板”。在“控制面板”中双击“管理工具”。在“管理工具”窗口中双击“本地安全策略”。在“安全设置”下打开“本地策略”文件夹。在“本地策略”文件夹中选择“安全选项”。在“策略”列中,找到“网络访问: 本地帐户的共享和安全模式”并双击它。在“网络访问: 本地帐户的共享和安全模式”对话框中,将设置从“仅来宾 - 本地用户以来宾身份验证”更改为“经典 - 本地用户以自己的身份验证”并单击“确定”。关闭该窗口并重新启动计算机。在远程计算机上重复步骤 1 到 8。现在就可以在两台计算机上使用相同的用户名进行远程调试了。警告 将安全模型更改为“传统型”可能会导致对共享文件和 DCOM 组件的意外访问。如果进行此更改,则远程用户可以使用您的本地用户帐户(而不是 Guest 帐户)进行身份验证。如果某个远程用户与您的用户名和密码匹配,则该用户将能够访问您已对外共享的任何文件夹或 DCOM 对象。
通过js保存图片到本地中遇到的跨域问题
html
meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\"
head
script
window.onload = function() {
draw();
var saveButton = document.getElementById(\"saveImageBtn\");
bindButtonEvent(saveButton, \"click\", saveImageInfo);
var dlButton = document.getElementById(\"downloadImageBtn\");
bindButtonEvent(dlButton, \"click\", saveAsLocalImage);
};
function draw(){
var canvas = document.getElementById(\"thecanvas\");
var ctx = canvas.getContext(\"2d\");
ctx.fillStyle = \"rgba(125, 46, 138, 0.5)\";
ctx.fillRect(25,25,100,100);
ctx.fillStyle = \"rgba( 0, 146, 38, 0.5)\";
ctx.fillRect(58, 74, 125, 100);
ctx.fillStyle = \"rgba( 0, 0, 0, 1)\"; // black color
ctx.fillText(\"Gloomyfish - Demo\", 50, 50);
}
function bindButtonEvent(element, type, handler)
{
if(element.addEventListener) {
element.addEventListener(type, handler, false);
} else {
element.attachEvent(\'on\'+type, handler);
}
}
function saveImageInfo ()
{
var mycanvas = document.getElementById(\"thecanvas\");
var image = mycanvas.toDataURL(\"image/png\");
var w=window.open(\'about:blank\',\'image from canvas\');
w.document.write(\"img src=\'\"+image+\"\' alt=\'from canvas\'/\");
}
function saveAsLocalImage () {
var myCanvas = document.getElementById(\"thecanvas\");
// here is the most important part because if you dont replace you will get a DOM 18 exception.
// var image = myCanvas.toDataURL(\"image/png\").replace(\"image/png\", \"image/octet-stream;Content-Disposition: attachment;filename=foobar.png\");
var image = myCanvas.toDataURL(\"image/png\").replace(\"image/png\", \"image/octet-stream\");
window.location.href=image; // it will save locally
}
/script
/head
body bgcolor=\"#E6E6FA\"
div
canvas width=200 height=200 id=\"thecanvas\"/canvas
button id=\"saveImageBtn\"Save Image/button
button id=\"downloadImageBtn\"Download Image/button
/div
/body
/html
好像这个可以 不错 你试一试吧 把下载下来的文件 重命名 为 图片格式 就可以预览啦