解决跨域问题 方案一:添加HTTP请求头 方案二:JSONP 方案三:HttpClient 方案四:Nginx
跨域:就是浏览器的安全机制,要求该工程请求的域名需要一致,如果说请求域名不一致的情况下,浏览器没有办法直接返回结果;
解决问题的方案:
JSONP方式;
Nginx方式;
HttpClient方式;
添加HTTP请求头方式;
后台response添加header,response.setHeader("Access-Control-Allow-Origin", "*"); 支持所有网站
项目搭建结构如下:创建两个独立的项目
后端代码:
package com.wn;
import com.alibaba.fastjson.JSON;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/aServlet")
public class AServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
//方法一:使用请求头解决跨域问题
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
System.out.println("数据:"+username);
//响应
resp.getWriter().write("success");
//添加请求头方式解决跨域
resp.setHeader("Access-Control-Allow-Origin","*");
}
}
前端代码:
<%--
Created by IntelliJ IDEA.
User: wn
Date: 2020/2/6
Time: 10:04
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>跨域</title>
<script type="text/javascript" src="js/jquery-1.8.3.min.js"></script>
<script>
//使用请求头解决跨域问题
$(function () {
$("#button").click(function () {
var username=$("#username").val();
$.ajax({
url:"http://www.aproject.com:8080/aServlet",
data:{"username":username},
type:"POST",
success:function (result) {
alert(result)
},
error:function () {
alert("error!!!")
}
})
})
})</script>
</head>
<body>
<input type="text" name="username" id="username"/><button id="button" type="button">提交</button>
</body>
</html>
方案二:JSONP
前端代码:
<%--
Created by IntelliJ IDEA.
User: wn
Date: 2020/2/6
Time: 10:04
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>跨域</title>
<script type="text/javascript" src="js/jquery-1.8.3.min.js"></script>
<script>
//使用JSONP方式解决跨域问题
$(function () {
$("#button").click(function () {
var username=$("#username").val();
$.ajax({
url:"http://www.aproject.com:8080/aServlet?username="+username,
type:"GET",
jsonp:"jsonp", //回调函数
dataType:"JSONP",
success:function (result) {
alert(result)
},
error:function () {
alert("error!!!")
}
})
})
})</script>
</head>
<body>
<input type="text" name="username" id="username"/><button id="button" type="button">提交</button>
</body>
</html>
后端代码:
package com.wn;
import com.alibaba.fastjson.JSON;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/aServlet")
public class AServlet extends HttpServlet {
//resp.setContentType("text/html;charset=utf-8");
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
//方法二:使用JSONP解决跨域问题
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
System.out.println("数据:"+username);
//使用JSONP解决跨域问题
String jsonp = req.getParameter("jsonp");
//需要将返回的数据转换为JSON格式
String success = JSON.toJSONString("success");
resp.getWriter().write(jsonp+"("+success+")");
}
}
jquery中jsonp的实现原理
在同源策略下,在某个服务器下的页面时无法获取到该服务器以外的数据的,即一般的ajax是不能进行跨域请求的。但是img,iframe,script等标签是个例外,这些标签可以通过src属性请求到其他服务器上的数据。利用script标签的开放策略,我们可以实现跨域请求数据,当然这需要服务器端的配合。jquery中ajax的核心是通过XmlHttpRequest获取非本业内容,而jsonp的核心则是动态添加,script标签来调用服务器提供的js脚本。
当我们正常地请求一个JSON数据的时候,服务端返回的是一串JSON类型的数据,而我们使用JSONP模式来请求数据的时候服务器返回的是一段可执行的JavaScript代码。因为JSONP跨域的原理就是用的动态加载,所以我们只能把参数通过URL的方式传递,所以JSONP的type类型只能是GET请求方式!
使用JSONP模式来请求数据的整个流程:客户端发送一个请求,规定一个可执行的函数名(这里就是jquery做了封装的处理,自动帮我们生成回调函数并把数据取出来供success属性方法来调用,而不是传递一个回调句柄),服务器端接受定义的函数名称,然后把数据通过实参的形式发送出去。
(在query源码中,JSONP的实现方式是动态添加script标签来调用服务器提供的JS脚本。jquery会在Window对象中加载一个全局的函数,当script代码插入时函数执行,执行完毕后就script标签会被移除。同时jquery还对非跨域的请求进行了优化,如果这个是在同一个域名下那么它就会像正常地ajax请求一样工作。)
JSONP的优缺点
JSONP的优点:它不像是XMLHttpRequest对象实现的ajax请求那样受到同源策略的限制,它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持,并且在请求完毕后可以通过调用callback的方式回传结果;
JSONP的缺点:它只支持GET请求而不支持POST等其他类型的HTTP请求,它只支持跨域HTTP请求这种情况下,不能解决不同域的两个页面之间如何进行JavaScript调用的问题;
方案三:HttpClient
前端代码:
<%--
Created by IntelliJ IDEA.
User: wn
Date: 2020/2/6
Time: 10:04
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>跨域</title>
<script type="text/javascript" src="js/jquery-1.8.3.min.js"></script>
<script>
//使用HttpClient方式解决跨域问题
$(function () {
$("#button").click(function () {
var username=$("#username").val();
$.ajax({
url:"httpServlet?username="+username,
type:"GET",
success:function (result) {
alert(result)
},
error:function () {
alert("error!!!")
}
})
})
})
</script>
</head>
<body>
<input type="text" name="username" id="username"/><button id="button" type="button">提交</button>
</body>
</html>
HttpClient类:
package com.wn;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import sun.net.www.http.HttpClient;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/httpServlet")
public class HttpCient extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建连接
CloseableHttpClient client = HttpClients.createDefault();
//请求
HttpGet httpGet=new HttpGet("http://www.aproject.com:8080/aServlet?username="+req.getParameter("username"));
//发送请求
CloseableHttpResponse response = client.execute(httpGet);
//获取返回结果 将A工程中的success提示语句返回给httpClient
String s = EntityUtils.toString(response.getEntity());
//响应 HttpClient将返回的结果响应给页面
resp.getWriter().write(s);
}
}
后端代码:
package com.wn;
import com.alibaba.fastjson.JSON;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/aServlet")
public class AServlet extends HttpServlet {
//resp.setContentType("text/html;charset=utf-8");
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
//方法三:使用HttpClient解决跨域问题
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
System.out.println("数据:"+username);
//响应
resp.getWriter().write("success");
}
}
实现原理
实现原理很简单,若想在B项目中通过ajax访问A项目获取结果,固然有ajax跨域问题,但是B项目中访问B项目获取结果,不存在跨域问题,这种方式实际上是在B项目中ajax请求范文B项目中的HttpClient,在通过HttpClient转发请求获取A项目中的数据结果。但这种方式产生了两次请求,效率低,但内部请求,比较安全。
方案四:Nginx
B项目不能直接请求A项目内容,可以通过Nginx,根据同域名,但项目名不同进行区分
当我们访问www.bproject.com通过www.nginx.com/B访问,并通过nginx转达到www.bproject.com
当我们访问www.aproject.com通过www.nginx.com/A访问,并通过nginx转达到www.aproject.com
server {
listen 80;
server_name www.nginx.com;
location /A {
proxy_pass http://www.aproject.com:8080;
index index.html index.htm;
}
location /B {
proxy_pass http://www.bproject.com:8081;
index index.html index.htm;
}
}