[转]Ajax跨域请求

一.编一个服务器端servlet

    @RequestMapping("/haha")
    @ResponseBody
    String haha(String haha, HttpServletRequest req, HttpServletResponse resp) {
        //resp.addHeader("Access-Control-Allow-Origin", "null");
        System.out.println(haha);
        System.out.println("you accessed!!!");
        return haha + " : " + req.getMethod();
    }

如果服务器回复的头部Access-Control-Allow-Origin属性中包含请求的Origin,那么客户端就可以通过ajax访问.

我用的是spring mvc,如果RequestMapping不带参数,默认为'/',相当于映射一切url;如果请求的url找不到,那就去找它.

无参数的RequestMapping只允许有一个,否则无法部署,报错.因为最后兜底的只能有一个servlet.

在spring mvc中,如果没有规定请求方式,默认是都可以,无论是get还是post都能够找到资源,只要url正确就行.

二.ajax方式请求

1.如果设置了头部就会出错(ajax设置了headers就会出错)

Response to preflight request doesn't pass access control check: 
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'null' is therefore not allowed access. The response had HTTP status code 403.

preflight意为起飞前,航前,pre 在...之前,flight航班

请求在起飞前没有通过,请求被扼杀在摇篮里.

 2.如果不设置头部,可以把请求发送出去

No 'Access-Control-Allow-Origin' header is present on the requested resource. 
Origin 'null' is therefore not allowed access.

下面用ajax请求这个servlet

<body>
    <h1 id='resp'></h1> 
        <input id='haha' type='text'></input> 
</body>
<script type="text/javascript">
    $('#haha').keydown(function(event) {
        console.log(event.which)
        if(event.which==13){
            $.get('http://localhost:8080/news/haha',{'haha':'wyf'},function(data){
                console.log(data)
                console.log('get over')
            })
        }
    });
</script>

服务器端输出了"you succeed!!!",这说明对于跨域请求服务器是搭理了的,问题出在服务器禁止返回或者是浏览器不允许用户查看返回的内容.

据我猜测,很有可能是后者,即:chrome分析返回结果,发现跨域了,于是不让用户看了.

如果用java代码通过httpclient或者urlConnection来实现,是能够收到回复的.所以很有可能,结果返回来了,浏览器不让看.

三.解决方案之修改服务器

只需要在服务器上添加一句允许Origin就可以了,如果允许任何一个网站访问,那么就设置为'*'就可以了.

resp.addHeader("Access-Control-Allow-Origin", "null");

四.解决方案之虚拟表单

解决方案很简单:编一个表单进行提交,因为只有ajax才存在跨域访问问题,而提交表单跟ajax不一样.

提交表单之后服务器端决定了浏览器端页面的跳转,把权力完全交给了服务器,而ajax只是通过服务器获取数据

下面的表单是可以提交成功的

    <form action='http://localhost:8080/news/haha' method="GET">
        <input id='haha' type='text'></input>
        <input type="submit"></input>
    </form>

可是填写表单太麻烦,于是可以虚拟表单并提交

    $(document).ready(function(){
        var form=$('<form></form>')
        $(form).attr({"action":'http://localhost:8080/news/haha',"method":'post'}).append("<input name='haha' value='haha weidiao'>")
        $(form).submit()
        console.log('haha')
    })

五.同源策略

同源策略(Same-Origin Policy)阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性。如果它们的协议、端口(如果指明了的话)和主机名都相同。则他们属于同源。

同源策略就是禁止外人访问我的资源,是一种安全机制.它是浏览器采用的策略.

六.jsonp

完全不同的两个域的访问,如www.360.cnwww.360safe.com的互相访问
这种情况通过javascript语言本身就无法解决了,需要借助<javascript>标签的特性和jsonp协议,在html文档里使用<javascript>标签时有个src属性,这个属性对于url的域名是没有任何限制的,jsonp全名json with padding。
一个简单的做法就是利回调函数
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title>Test Jsonp</title>
<script type="text/javascript">
         function jsonpCallback(result)
         {
alert(result.msg);
         }
     </script>
<script type="text/javascript" src="http://test.com/test.php?jsonp=jsonpCallback"></script>
</head>
<body>
</body>
</html>
 
服务端的代码:
<?php
echo $_GET['jsonp']."({msg:'this is json data'})";
?>  

从JSONP的原理来看的话,script标签只能GET方式。还有就是后台程序需要对callback参数进行有效性过滤,不然恶意用户可以插入攻击代码了。一般使用正则:

^[a-z0-9_]+$

来判断用户的回调函数名是否合法。

七.浏览器不让看

chrome 等浏览器 对于 跨域请求并要求设置Headers自定义参数的时候的 "预请求"   就是如果遇到 跨域并设置headers的请求,所有请求需要两步完成!

A 第一步:发送预请求 OPTIONS 请求。此时 服务器端需要对于OPTIONS请求作出响应 一般使用202响应即可 不用返回任何内容信息。

B 第二步:服务器accepted 第一步请求后 浏览器自动执行第二步 发送真正的请求。此时 大多数人 会发现请求成功了,但是 有那么几个人会发现 请求成功了但是没有任何信息返回 why?因为你自定义的请求头在服务器响应中不存在!

原文地址:https://www.cnblogs.com/DarrenChan/p/6068996.html