JavaWeb跨域问题常用解决办法汇总
Posted 晨港飞燕
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaWeb跨域问题常用解决办法汇总相关的知识,希望对你有一定的参考价值。
一.问题抛出
前后端调试过程中,浏览器经常出现下面的错误,出现Access-Control-Allow-Origin的字眼,就是跨域问题
二.什么是跨域
当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
当前页面url | 被请求页面url | 是否跨域 | 原因 |
http://www.test.com/ | http://www.test.com/index.html | 否 | 同源(协议、域名、端口号相同) |
http://www.test.com/ | https://www.test.com/index.html | 跨域 | 协议不同(http/https) |
http://www.test.com/ | http://www.baidu.com/ | 跨域 | 主域名不同(test/baidu) |
http://www.test.com/ | http://blog.test.com/ | 跨域 | 子域名不同(www/blog) |
http://www.test.com:8080/ | http://www.test.com:7001/ | 跨域 | 端口号不同(8080/7001) |
三.为什么会出现跨域问题
出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)
非同源限制:
【1】无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB
【2】无法接触非同源网页的 DOM
【3】无法向非同源地址发送 AJAX 请求
四.跨域常用解决方法
1.JSONP
JSONP 是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,兼容性好(兼容低版本IE),缺点是只支持get请求,不支持post请求。
核心思想:网页通过添加一个<script>元素
,向服务器请求 JSON 数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来
- jQuery ajax:
$.ajax(
url: 'http://www.test.com:8080/login',
type: 'get',
dataType: 'jsonp', // 请求方式为jsonp
jsonpCallback: "handleCallback", // 自定义回调函数名
data:
);
- Vue.js
this.$http.jsonp('http://www.domain2.com:8080/login',
params: ,
jsonp: 'handleCallback'
).then((res) =>
console.log(res);
)
2.CORS
CORS 是跨域资源分享(Cross-Origin Resource Sharing)的缩写。它是 W3C 标准,属于跨源 AJAX 请求的根本解决方法。
1、普通跨域请求:只需服务器端设置Access-Control-Allow-Origin
2、带cookie跨域请求:前后端都需要进行设置
前端设置:
根据xhr.withCredentials字段判断是否带有cookie
-
jQuery ajax
$.ajax(
url: 'http://www.test.com:8080/login',
type: 'get',
data: ,
xhrFields:
withCredentials: true // 前端设置是否带cookie
,
crossDomain: true, // 会让请求头中包含跨域的额外信息,但不会含cookie
);
-
vue-resource
Vue.http.options.credentials = true
-
axios
axios.defaults.withCredentials = true
服务端设置:
服务器端对于CORS的支持,主要是通过设置Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。
- Java后台
/*
* 导入包:import javax.servlet.http.HttpServletResponse;
* 接口参数中定义:HttpServletResponse response
*/
// 允许跨域访问的域名:若有端口需写全(协议+域名+端口),若没有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com");
// 允许前端带认证cookie:启用此项后,上面的域名不能为'*',必须指定具体的域名,否则浏览器会提示
response.setHeader("Access-Control-Allow-Credentials", "true");
// 提示OPTIONS预检时,后端需要设置的两个常用自定义头
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
3.nginx代理
使用Nginx转发请求。把跨域的接口写成调本域的接口,然后将这些接口转发到真正的请求地址。
安装好Nginx后,修改nginx.conf文件,把默认的server配置注释掉。
在下面增加:
server
# 监听9099端口
listen 9099;
# 域名是localhost
server_name localhost;
#凡是localhost:9099/api这个样子的,都转发到真正的服务端地址http://localhost:9871
location ^~ /api
proxy_pass http://localhost:9871;
为什么不直接监听9871,因为nginx监听9871,就会占用此端口,本地开发就不能以9871端口启用
4.vue代理
在vue开发中实现跨域:在vue项目根目录下找到vue.config.js文件(如果没有该文件则自己创建),在proxy中设置跨域
devServer:
proxy: //配置跨域
'/api':
target: 'http://121.121.67.254:8185/', //这里后台的地址模拟的;应该填写你们真实的后台接口
changOrigin: true, //允许跨域
pathRewrite:
/* 重写路径,当我们在浏览器中看到请求的地址为:http://localhost:8080/api/core/getData/userInfo 时
实际上访问的地址是:http://121.121.67.254:8185/core/getData/userInfo,因为重写了 /api
*/
'^/api': ''
,
,
在创建axios实例的时候将baseURL设置为/api ,这时候我们的跨域就已经完成了。
// 创建axios实例
const service = axios.create(
baseURL: /api, // api的base_url
timeout: 60000 // 请求超时时间
)
在vue中使用proxy进行跨域的原理是:将域名发送给本地的服务器(启动vue项目的服务,loclahost:8080),再由本地的服务器去请求真正的服务器。
问:proxyTable 里面的pathRewrite里面的‘^/api’:'' 什么意思?
答:用代理, 首先你得有一个标识, 告诉他你这个连接要用代理. 不然的话, 可能你的 html, css, js这些静态资源都跑去代理. 所以我们只要接口用代理, 静态文件用本地.
'/
api':
, 就是告诉node
, 我接口只要是'/
api'
开头的才用代理.所以你的接口就要这么写 /
api/xx/xx
. 最后代理的路径就是 http://xxx.xx.com/
api/xx/xx
.
可是不对啊, 我正确的接口路径里面没有/
api啊. 所以就需要 pathRewrite
,用''^/
api'':''
, 把'/
api'
去掉, 这样既能有正确标识, 又能在请求接口的时候去掉api.
5.nginx配置
location ~* \\.(eot|ttf|woff)$
add_header Access-Control-Allow-Origin '*';
Access-Control-Allow-Origin:* 表示允许任何域名跨域访问。
扩展
server
listen 80;
server_name uedbox.com;
location /
# Simple requests
if ($request_method ~* "(GET|POST)")
add_header "Access-Control-Allow-Origin" *;
# Preflighted requests
if ($request_method = OPTIONS )
add_header "Access-Control-Allow-Origin" *;
add_header "Access-Control-Allow-Methods" "GET, POST, OPTIONS, HEAD";
add_header "Access-Control-Allow-Headers" "Authorization, Origin, X-Requested-With, Content-Type, Accept";
return 200;
....
# Handle request
....
还可以动态配置跨域方案
set $cors '';
if ($http_origin ~ '^https?://(localhost|www\\.yourdomain\\.com|www\\.yourotherdomain\\.com)')
set $cors 'true';
if ($cors = 'true')
add_header 'Access-Control-Allow-Origin' "$http_origin" always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;
# required to be able to read Authorization header in frontend
#add_header 'Access-Control-Expose-Headers' 'Authorization' always;
if ($request_method = 'OPTIONS')
# Tell client that this pre-flight info is valid for 20 days
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
以上是关于JavaWeb跨域问题常用解决办法汇总的主要内容,如果未能解决你的问题,请参考以下文章