AngularJS跨域問題 ajax 跨域

先看代碼:

$http({
                    method: 'POST',
                    //withCredentials: true, //這個用來將cookie傳回服務器,可是post請求設置這個將致使error
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded',//跨站必須,不然瀏覽器自動將method改成options  
                    },
                    url: 'http://192.168.14.136:8888/api/v1.0/login/',
                    data: data1,
                    /*transformRequest: function(obj) {//這個用來把json變爲p1=v1&p2=v2這種形式
                        var str = [];
                        for (var p in obj) {
                            str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
                        }
                        return str.join("&");
                    }*/
                }).success(function(data) {
                    alert(data);
                }).error(function(data) {
                    alert(data);
                });

//服務器端必須返回頭以下才會success
response.setHeader("Access-Control-Allow-Origin", "*");//若是要傳遞cookie這裏不能使用通配符,而是要用下面的方式
response.addHeader("Access-Control-Allow-Credentials", "true"); //接受cookie傳遞  
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); //匹配客戶端發來的Origin並返回去,這樣ajax才能success。 
response.setHeader("Access-Control-Allow-Methods","POST");
response.setHeader("Access-Control-Allow-Headers","x-requested-with,content-type");


python:
        self.set_header("Content-Type","application/json")
        self.set_header("Access-Control-Allow-Origin",self.request.headers.get("Origin", "*"))
        self.set_header("Access-Control-Allow-Credentials","true")
        self.set_header("Access-Control-Allow-Methods","POST,GET,OPTIONS")
        self.set_header("Access-Control-Allow-Headers","x-requested-with,content-type")

注意:返回json的格式必須嚴謹,不然會ajax err

 

一:案例實現

從網上下載了一個AngularJS項目,配置啓動後發現數據發送不到本身的後臺中去,老是提示跨域問題。javascript

下面是AngularJS的部分代碼:html

 

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html ng-app="">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta http-equiv="Access-Control-Allow-Origin" content="*">
    <title>AngularJSTest</title>
</head>
<body ng-controller="MyController">
<p>User</p>
<p>ID</p>
<input id="id" name="id" ng-model="saveUser.id">
<br>
<p>Name</p>
<input id="id" name="name" ng-model="saveUser.name">
<br>
<p>age</p>
<input id="id" name="age" ng-model="saveUser.age">
<br>
<ul>
    <li ng-repeat="x in infos">
        {{ x.ID + x.name + x.age }}
    </li>
</ul>
<button ng-click="getUser()">提交</button>
<script>
    function MyController($scope, $http){
        $scope.saveUser = {
            id:1,
            name:"John",
            age:"16"

        };
        $scope.getUser = function(){
            $http({
                method: "POST",
                url: "http://localhost:8080/Spring-MVC/AngularJS/getUser.do",
                data: $scope.saveUser
            }).success(function (data){
                $scope.infos = data;
            })
        };
    }
</script>
<script src="lib/angular/angular.js"></script>
</body>
</html>

注意:在$http中URL前部分爲後臺項目的路徑。前端

 

後臺須要本身寫一個過濾器,並配置到web.xml中去java

 

package com.jxq.util;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

public class RequestFilter implements Filter {

	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub

	}

	public void doFilter(ServletRequest request, ServletResponse pResponse, FilterChain chain)
			throws IOException, ServletException {
		// TODO Auto-generated method stub
		HttpServletResponse response = (HttpServletResponse) pResponse;
		response.setHeader("Access-Control-Allow-Origin", "*");
		response.setHeader("Access-Control-Allow-Methods", "POST,GET,DELETE,PUT");
		response.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
		
		chain.doFilter(request, response);
	}

	public void destroy() {
		// TODO Auto-generated method stub

	}

}

web.xml中的配置python

 

 

<filter>
  		<filter-name>requestFilter</filter-name>
  		<filter-class>com.jxq.util.RequestFilter</filter-class>
  	</filter>
  	<filter-mapping>
  		<filter-name>requestFilter</filter-name>
  		<url-pattern>*.do</url-pattern>
  	</filter-mapping>

Controller的寫法:web

 

 

package com.jxq.controller.user;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.jxq.entity.user.AngularUser;
import com.jxq.service.user.UserOperate;

@Controller
@RequestMapping(value="/AngularJS")
public class UserController {
	@Autowired
	private UserOperate userOperate;
	
	@RequestMapping(value="/getUser.do", method=RequestMethod.POST)
	@ResponseBody
	public List<AngularUser> save(@RequestBody AngularUser angularUser){
		System.out.println("ID:" + angularUser.getId());
        System.out.println("name:" + angularUser.getName());
        System.out.println("age:" + angularUser.getAge());
        List<AngularUser> lists = new ArrayList<AngularUser>();
        AngularUser user1 = new AngularUser();
        user1.setId("001");
        user1.setAge("25");
        user1.setName("zhangsan");
        lists.add(user1);
        AngularUser user2 = new AngularUser();
        user2.setId("002");
        user2.setAge("26");
        user2.setName("lisi");
        lists.add(user2);
        AngularUser user3 = new AngularUser();
        user3.setId("003");
        user3.setAge("27");
        user3.setName("wangwu");
        lists.add(user3);
        return lists;
	}
}

必需要加上@responseBody,不然沒法返回數據給前端,稍後的博客會詳細介紹@requestBody和@responseBodyajax

 

二:跨域問題詳解

下面詳細說一下AngularJS的$http請求跨域,此部分爲網上查詢獲得。spring

跨域,前端開發會常常碰見,AngularJS實現跨域方式相似於Ajax,使用的是CORS機制。json

1:CORS機制:

是一種容許當前域的資源被其餘域的腳本請求訪問的機制。整個請求都是瀏覽器自動完成,不須要用戶參與,會自動添加一些附加的頭信息,有時候會多發出一次附加的請求。api

分爲兩種:簡單請求和非簡單請求。

區別在於只要知足兩類條件,就是簡單請求。

(1):請求方法是一下三種方法之一:HEAD、GET和POST

(2):請求的頭信息不超過一下幾種字段:

Accept、Accept-Language、Content-Language、Last-Event-ID和Content-Type

其中Content-Type的值:application/x-www-form-urlencoded、multipart/form-data和text/plain

凡是不知足上述兩個條件的,都是非簡單請求。瀏覽器對於這兩種請求的處理方式是不同的。

a:簡單請求

對於簡單請求,瀏覽器直接發出CORS請求,就是在頭信息中會增長一個Origin字段.

Origin字段用來講明本次請求來自哪一個源(協議+域名+端口),服務器根據這個值,決定是否贊成此次請求。

若是是不在許可範圍內,服務器會返回一根正常的HTTP迴應,可是沒有包括Access-Control-Allow-Origin字段,就知道是出錯了,從而跑出錯誤,被XMLHttpRequest的onerror回調函數捕獲。

注意:這種錯誤是沒法經過狀態碼識別,由於HTTP迴應多是200。

若是Origin制定的域名在許可範圍內,服務器返回的響應,就會多幾個頭信息字段。

紅色框括起來的,是可CORS請求想看的字段,都是以Access-Control-開頭

(1):Access-Control-Allow-Origin

該字段是必須的。它的值要麼是請求時Origin字段的值,要麼是一個*,表示接受任何域名的請求。

(2):Access-Control-Allow-Credentials

可選,是一個布爾值,表示是否容許發送Cookie,默認狀況下,Cookie不包括在CORS請求之中,設爲true,即表示服務器明確許可,Cookie能夠包含在請求中,一塊兒發送給服務器。這個值也只能設爲true。若是不須要瀏覽器發送Cookie給服務器,刪除便可。

(3):Access-Control-Expose-Headers

可選,CORS請求時,XMLHttpRequest對象的getResponseHeader()方法只能拿到6個基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。若是想拿到其餘字段,就必須在Access-Control-Expose-Headers裏面指定。上面的例子指定,getResponseHeader('FooBar')能夠返回FooBar字段的值。

b:非簡單請求

是那種對服務器有特殊要求的請求,請求方法是PUT或DELETE,或者Content-Type類型爲application/json

首先是預檢測:在正式通信以前,發送一次查詢請求,詢問是否在許可名單中以及可使用那些HTTP動詞和頭信息。只有獲得答覆,纔會正式發起請求,不然報錯。

預檢測經過以後,瀏覽器就會發送一個正常的請求。

c:與JSONP的比較

JSONP只支持GET請求,CORS支持全部的類型的HTTP請求。JSONP的優點在於支持老式瀏覽器,以及能夠向不支持CORS的網站請求數據。

2:AngularJS的$http

AngularJS的$http請求方式:

 

$http.post(url, data, [config]).success(function(){ ... });
$http.get(url, [config]).success(function(){ ... });

(1):JSONP方式:

指定callback和回調函數名,函數名爲JSON_CALLBACK時,會調用success回調函數,JSON_CALLBACK必須全爲大寫。

$http.jsonp("http://localhost/sitesettings/getBadgeInfo.pt?jsonp=JSON_CALLBACK&siteid=137bd406").success(function(data){ ... });

(2):get方式

前端代碼:

function getAdustryController($scope,$http){
	$http.get('http://localhost/ajax/getAllIndustryCategoty.pt?languageColumn=name_eu').success(function(data){
		$scope.industries = data;
	});
}

 

(3)POST請求:

 

在服務端設置容許在其餘域名下訪問、響應類型、響應頭

 

response.setHeader("Access-Control-Allow-Origin", "*");
		response.setHeader("Access-Control-Allow-Methods", "POST,GET,DELETE,PUT");
		response.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");

在服務端設置:

response.setHeader("Access-Control-Allow-Origin", "*");
		response.setHeader("Access-Control-Allow-Methods", "POST,GET,DELETE,PUT");
		response.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
相關文章
相關標籤/搜索