跨域訪問

緣由:同源策略javascript

1.JSONP

Ajax直接請求普通文件存在跨域無權限訪問的問題 ,數據沒法請求,可是 script 請求js確能夠正常訪問。html

jsonp就是模仿一個 script請求 來獲取數據的方式,全部基本支持的是 GET 請求前端

$.ajax({
   async: false,
   type: 'get',
   jsonp: "callback",//設置這個會替換瀏覽器發送請求時地址後面自動添加的?callback=xxx中的callback這個字,通常狀況下不用傳這個參數
   jsonpCallback: "callJsonP",//這個值將用來取代jQuery自動生成的隨機函數名,也就是上句話中的'xxx'。
   data:自定義
   url: 'http://lnn.wuage.com:8080/pc/toJson',
   dataType: 'jsonp',
   success: function (data) {
      alert(JSON.stringify(data));
   }
});
@RequestMapping("/toJson")
@ResponseBody
public String  toJson(HttpServletRequest request,@RequestParam(value="callback")String callback)
{
   return callback + "(" + new JSONObject() + ")";
   //或者 fastJSON
   JSONObject obj=new JSONObject();
   obj.put("data","你好呀");
   JSONPObject result=new JSONPObject("callJsonP");
   result.addParameter(obj);
   String resultStr=result.toString();
   return resultStr;
}

 

2.設置 CORS協議

適用場景:承載的信息量大,get形式搞不定,需選用post傳輸。CORS支持全部類型的傳輸。java

兼容性:移動端全面支持(除opera mini),PC上IE8+。jquery

經常使用頭web

Access-Control-Allow-Origin: http://foo.org

Access-Control-Max-Age: 3628800

Access-Control-Allow-Methods: GET,PUT, DELETE

Access-Control-Allow-Headers: content-type

"Access-Control-Allow-Origin"代表它容許"http://foo.org"發起跨域請求

"Access-Control-Max-Age"代表在3628800秒內,不須要再發送預檢驗請求,能夠緩存該結果

"Access-Control-Allow-Methods"代表它容許GET、PUT、DELETE的外域請求

"Access-Control-Allow-Headers"代表它容許跨域請求包含content-type頭

1.簡單請求

     只使用 GET, HEAD 或者 POST 請求方法:若是使用 POST 向服務器端傳送數據,則數據類型(Content-Type)只能是 application/x-www-form-urlencoded, multipart/form-data 或 text/plain中的一種ajax

    不會使用自定義請求頭(相似於 X-Modified 這種):HTTP頭部信息不超出如下{Accept,Accept-Language,Content-Language,Last-Event-ID,content-type(只限於上面提到的3種類型)}spring

 失敗狀況json

     

       若是這個源不在許可範圍內,會報錯: No 'Access-Control-Allow-Origin' header is present on the requested resource.api

      對於簡單請求,瀏覽器直接發出CORS請求。瀏覽器會自動在頭信息(Request Headers)中,添加一個Origin 字段,來代表本次請求來自哪一個域。

      若是Origin指定的域名在許可範圍內(必須是跨域了的),Response Headers中會多出幾個頭信息字段。

Access-Control-Allow-Credentials:true//值爲true表示容許發送cookie
Access-Control-Allow-Methods:GET, POST, OPTIONS
Access-Control-Allow-Origin:http://localhost:8080
Access-Control-Max-Age:1728000

例如

withCredentials屬性

由於CORS默認不發送cookie和http認證,若是要把Cookie發到服務器,就要指定Access-Control-Allow-Credentials:true;

@CrossOrigin(origins="*",allowCredentials="true")
或者
response.setHeader("Access-Control-Allow-Credentials","true");

另外AJAX中也要打開withCredentials屬性。

var xhr=new XMLHttpRequest();
xhr.withCredentials=true;

jquery ajax請求參數中加入

xhrFields: {
  withCredentials: true
}

2.非簡單請求

除了上面說的簡單請求外都是非簡單請求,好比:請求方法是PUT
或DELETE,或者Content-Type字段的類型是application/json,又或者有自定義請求頭Access-Control-Request-Headers: X-Custom-Header。

好比,我添加自定義請求頭

xhr.setRequestHeader('Some-Custom-Response-Header', 'value');

就會發現連續向同一地址請求了兩次

第一次 options 請求

第二次請求:真實請求

這是由於瀏覽器發現,這是一個非簡單請求,就自動發出一個"預檢"請求,要求服務器確承認以這樣請求。"預檢"請求用的請求方法是OPTIONS,表示這個請求是用來詢問的。"預檢"請求以後,瀏覽器球會進行正常CORS請求。

3.服務器代碼

方法1、 HttpServletRequest :

         在方法體內使用 HttpServletRequest 進行跨越參數設置。若是有參數,必須參數符合要求才進行  

          跨越參數設置。不然報錯  400 bad requset,無返回信息

@RequestMapping("/toJson",method = RequestMethod.POST,produces="application/json; charset=utf-8")
@ResponseBody
public String  toJson(HttpServletRequest request)
{
   //設置哪些域名能夠訪問---若是方法有參數直接報 400 bad request 錯誤
   response.setHeader("Access-Control-Allow-Origin", "*");
   //解決亂碼,緣由 springmvc 設置 produces="application/json; charset=utf-8" 未生效
   response.setContentType( "application/json; charset=utf-8" );
   return new JSONObject();
}

方法2、 @CorssOrigin:

       使用 @CorssOrigin 在進方法體之間就對跨域參數作出設置。發生錯誤有返回信息。

      Controller中的action的請求方法是實際方法就能夠,options方法默認支持

@CrossOrigin(origins="*")/**方法一:跨越參數有返回,有參時報錯參數缺失*/
@RequestMapping(value="/toJson",method = {RequestMethod.GET},produces="application/json;charset=utf-8")
@ResponseBody
public String  toJson(HttpServletRequest request,HttpServletResponse response){
     return new JSONObject("ni你好點的");
}

方法三、基於XML的配置

<mvc:cors>
    <mvc:mapping path="/api/**"
        allowed-origins="*"
        allowed-methods="GET,POST,PUT,OPTIONS"
        allow-credentials="false"
        max-age="3600" />
</mvc:cors>

方法4、基於java代碼的全局配置 (SpringMVC 4)

       支持SpringMvc 4以上  ,測試未生效

  • 在requestMapping中使用註解。
  • 全局實現 .定義類繼承WebMvcConfigurerAdapter
  • 將該類注入到容器中:
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
            .allowedOrigins("http://domain2.com")
            .allowedMethods("PUT", "DELETE")
            .allowedHeaders("header1", "header2", "header3")
            .exposedHeaders("header1", "header2")
            .allowCredentials(false).maxAge(3600);
    }
}

注入:

<bean class="com.tmall.wireless.angel.web.config.CorsConfigurerAdapter"></bean>

方法5、攔截器配置

1.使用 Spring 提供的 攔截器

<mvc:interceptors>  
   <mvc:interceptor> 
     <!--過濾的路徑--> 
     <mvc:mapping path="/h5/*" />  
     <bean class="com.wuage.ossserver.web.Interceptor.CorsInterceptor">  
       <!--過濾路徑中的不須要過濾的路徑-->
       <property name="excludedUrls">  
          <list>  
            <value>/h5/testOrigin</value>  
          </list>  
       </property>  
     </bean>  
   </mvc:interceptor>
<mvc:interceptors>
package com.wuage.ossserver.web.Interceptor;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**  
 * 請求攔截器,處理跨域問題  
 * @author 李寧寧  
 *  
 */  
public class CorsInterceptor implements HandlerInterceptor {  
  
    private List<String> excludedUrls;  
  
    public List<String> getExcludedUrls() {  
        return excludedUrls;  
    }  
  
    public void setExcludedUrls(List<String> excludedUrls) {  
        this.excludedUrls = excludedUrls;  
    }  
  
    /**  
     *   
     * 在業務處理器處理請求以前被調用 若是返回false   
     * 從當前的攔截器往回執行全部攔截器的afterCompletion(),  
     * 再退出攔截器鏈, 若是返回true 執行下一個攔截器,  
     * 直到全部的攔截器都執行完畢 再執行被攔截的Controller  
     * 而後進入攔截器鏈,  
     * 從最後一個攔截器往回執行全部的postHandle()  
     * 接着再從最後一個攔截器往回執行全部的afterCompletion()  
     *   
     * @param  request  
     *   
     * @param  response  
     */  
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,  
            Object handler) throws Exception {  
        //* 能夠替換成 特定的 網址(協議 域名 端口)
        response.setHeader("Access-Control-Allow-Origin", "*");  
        response.setHeader("Access-Control-Allow-Methods", "*");  
        response.setHeader("Access-Control-Max-Age", "3600");  
        response.setHeader("Access-Control-Allow-Headers",  
                "Origin, X-Requested-With, Content-Type, Accept");  
        response.setHeader("Access-Control-Allow-Credentials",  
                "true");
        return true;  
    }  
  
    // 在業務處理器處理請求執行完成後,生成視圖以前執行的動做  
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,  
            ModelAndView modelAndView) throws Exception {  
  
    }  
  
    /**  
     *   
     * 該方法也是須要當前對應的Interceptor的preHandle方法的返回值爲true時纔會執行。
     * 該方法將在整個請求完成以後,也就是DispatcherServlet渲染了視圖執行, 這個方法的主要做用是用於清理資源的, 
     *   
     * @param request  
     *   
     * @param response  
     *   
     * @param handler  
     *   
     */  
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,  
            Object handler, Exception ex) throws Exception {  
  
    } 
}

2. Filter 攔截器

<filter>
   <filter-name>cros</filter-name> 
   <filter-class>com.wuage.ossserver.web.Interceptor.CORSFilter</filter-class>
</filter>
<filter-mapping>
   <filter-name>cros</filter-name>
   <url-pattern>/h5/*</url-pattern>
</filter-mapping>
public class CORSFilter implements Filter  {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException,ServletException {
        HttpServletResponse localHttpServletResponse = (HttpServletResponse)response;
        localHttpServletResponse.addHeader("Access-Control-Allow-Origin", "*");
        localHttpServletResponse.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE,OPTIONS");
        localHttpServletResponse.addHeader("Access-Control-Allow-Headers", "Content-Type");
        localHttpServletResponse.addHeader("Access-Control-Max-Age", "1800");
        filterChain.doFilter(request, response);  
    }

    @Override
    public void destroy() {}

    @Override
    public void init(FilterConfig arg0) throws ServletException {}

}

注意: 使用 方法 1,2 控制器中只須要進行 特定的方法設置,無需就添加 例如 options類型的設計

        options 非簡單CORS請求中 嗅探 方法類型

4.前端

<input type="file" id="file_upload"/>
<input type="button" value="上傳圖片" id="upload"/>
function ajaxFileUpload(){
        var formData = new FormData();
        formData.append('file',$("#file_upload")[0].files[0]);    //將文件轉成二進制形式
        $.ajax({
            type:"post",
            url:"http://localhost:8080/nitshareserver/serve/fileupload",
            async:false,
            contentType: false,    //這個必定要寫
            processData: false, //這個也必定要寫,否則會報錯
            data:formData,
            dataType:'text',    //返回類型,有json,text,HTML。這裏並無jsonp格式,因此別妄想能用jsonp作跨域了。
            xhrFields: {withCredentials: true}, //設置是否帶驗證 cookie
            success:function(data){
                alert(data);
            },
            error:function(XMLHttpRequest, textStatus, errorThrown, data){
                alert(errorThrown);
            }            
        });
    }

5.補充

Springmvc模式是掛壁OPTIONS請求的,因此須要開啓

<servlet>    
   <servlet-name>application</servlet-name>    
   <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
   <init-param>  
        <param-name>dispatchOptionsRequest</param-name>  
        <param-value>true</param-value>  
   </init-param>    
   <load-on-startup>1</load-on-startup>    
</servlet>

 

6.常見錯誤:

              403 forbidden 無權限訪問-有時 forbox 好使,chrom 很差使

              400 bad request  請求失敗, 參數不符合要求

              301 服務器錯誤 或者 重定向

              405 Method Not Allowed :方法錯誤(複雜請求要求有 options 方法)

7.參考:

         https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

          https://my.oschina.net/wangnian/blog/689020

          http://www.tuicool.com/articles/Vf2aym

          http://blog.csdn.net/u012562943/article/details/53141991

          cookies:http://www.ruanyifeng.com/blog/2016/04/cors.html

          http://www.jianshu.com/p/7257e7c60ef5

相關文章
相關標籤/搜索