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项目,配置启动后发现数据发送不到自己的后台中去,总是提示跨域问题。

下面是AngularJS的部分代码:

<!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中去

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中的配置

<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的写法:

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和@responseBody

二:跨域问题详解

下面详细说一下AngularJS的$http请求跨域,此部分为网上查询得到。

跨域,前端开发会经常遇见,AngularJS实现跨域方式类似于Ajax,使用的是CORS机制。

1:CORS机制:

是一种允许当前域的资源被其他域的脚本请求访问的机制。整个请求都是浏览器自动完成,不需要用户参与,会自动添加一些附加的头信息,有时候会多发出一次附加的请求。

分为两种:简单请求和非简单请求。

区别在于只要满足两类条件,就是简单请求。

(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");

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏web前端教室

为什么现在各大招聘网站上要求会vue.js多?

2、angular适合做大型系统开发,它自带全家桶,本身不是很灵活。但这反而减少了出错的机率。

34820
来自专栏前端新视界

Ng-Matero:基于 Angular Material 搭建的中后台管理框架

目前市面上关于 Angular Material 的后台框架比较少,大多都是收费主题,而且都不太好用。

12520
来自专栏达达前端

【一起来烧脑】读懂WebApp知识体系

很多小白知道什么是app,但是却不知道什么是webapp呢,webapp是指用HTML5编写的移动web应用

10930
来自专栏生南星

浅谈Angular

AngularJS 是一个 JavaScript框架。它是一个以 JavaScript 编写的库。它可通过 <script> 标签添加到HTML 页面。

9810
来自专栏h5

angular聊天IM实例|仿微信angular版|NG2案例

运用angular+@angular/cli+@angular/router+@ngrx/store等技术实现开发的移动端聊天室angular版,实现了下拉刷新...

39840
来自专栏ionic3+

Ionic-cli/Angular-cil修改创建的“app”前缀

ionic-cli或angular-cli能很好地辅助开发,其中generate很方便地创建各种模版内容,即:

12850
来自专栏finleyMa

Angular 修改build后的静态资源目录路径

如果你通过angular-cli创建了一个angular项目,比如名称为angular-quick-start执行ng build后,静态资源会输出到dist/...

44820
来自专栏宋先生的Coding之旅

AngularJS入门 & 分页 & CRUD示例

AngularJS 诞生于2009年,由Misko Hevery 等人创建,后为Google所收购。是一款优秀的前端JS框架,已经被用于Google的多款产...

16340
来自专栏AndroidTv

Angular(06)- 为什么数据变化,绑定的视图就会自动更新了?

这里提一点,前端三大框架(Angular,React,Vue)的数据驱动来更新视图的原理,即 MVVM 的实现。 为什么数据发生变化,绑定的视图就会刷新了呢?

9310
来自专栏DotNet Core圈圈

【译】.NET Core 3.0 Preview 3中关于ASP.NET Core的更新内容

.NET Core 3.0 Preview 3已经推出,它包含了一系列关于ASP.NET Core的新的更新。

11410

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励