html 触发请求,跨域请求触发浏览器复杂请求

在做webapp的项目 常用的技术架构是 angularjs+api , 在调用api 的时候一般都是跨域请求

手机端的高级浏览器对跨域的支持很好,但是在跨域的情况下还有需求意想不到的情况

发送请求的时候 设置不同的响应头会导致浏览器不同的情况,发送一些头会导致浏览器发送一个复杂请求

复杂请求中 会先发送一个 OPTIONS 的请求,这个请求并不是开发者代码中的主动发出 而是浏览器发送的

在 移动3G 的网络情况下 , OPTIONS 的响应数度很慢 虽然不会超时(60s)

OPTIONS 是一个 预请求 , 目的是先请求下这个接口是否可请求 有权限读取,这是一个好的设计

但是 从另一面来讲,多发送一个请求 性能上有损失,移动3G在对OPTIONS请求的传递响应巨慢

js原生发送一个http请求

ajax对象1var xhr = new XMLHttpRequest();

开启连接口1

2

3

4xhr.open(method, , async)

method 请求方法

请求地址

async 是否异步

设置请求头1xhr.setRequestHeader(key, val)

发送1

2xhr.send(data)

data 如果是POST请求 data 就是body体的内容 其他情况为 null 就ok 了

设置响应1

2

3

4

5

6

7xhr.onreadystatechange = function () {

if (xhr.readyState == 4) {

if (xhr.status == 200) {

//

}

}

}

一个原生ajax源码封装

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136window.ajax = (function (){

/**

* 实例化并返回ajax对象

* @return {[type]} [description]

*/

var getXHR = function (){

var xhr = null;

if (typeof XMLHttpRequest != "undefined") {

xhr = new XMLHttpRequest();

}

else if (typeof ActiveObject != "undefined") {

var versions = [

"MSXML2.XMLHttp.6.0",

"MSXML2.XMLHttp.3.0",

"MSXML2.XMLHttp",

];

for (var i = 0; i < versions.length; i++) {

try {

xhr = new ActiveObject(versions[i]);

}

catch (e) {

//

}

}

}

else {

throw new Error('浏览器不支持ajax');

}

return xhr;

}

/**

* 设置发送请求是需要的参数

* @param {[type]} options [description]

* @return {[type]} [description]

*/

var settings = function (options){

var opt = {};

// method

opt.method = typeof options.method == "undefined" ? "GET" : options.method.toUpperCase();

if (!isAllowMethod(opt.method)) {

opt.method = "GET";

}

// gateway

opt.url = options.url;

if (typeof opt.url == "undefined") {

throw new Error("请填写请求的地址");

}

// data

opt.data = typeof options.data == "undefined" ? null : parseParams(options.data);

if (opt.method == "GET" && opt.data != null) {

opt.url = '?' + opt.data;

}

return opt;

}

/**

* 检查是否是允许的http请求方式

* @param {[type]} method [description]

* @return {Boolean} [description]

*/

var isAllowMethod = function (method){

var allows = ["GET", "POST", "PUT", "HEAD", "OPTIONS", "DELETE", "TRACE", "CONNECT"];

for (var i = 0; i < allows.length; i++) {

if (allows[i] == method) {

return true;

}

}

return false;

}

/**

* 处理请求是后的参数

* @param {[type]} data [description]

* @return {[type]} [description]

*/

var parseParams = function (data){

var params = '';

for (var key in data) {

params += key + '=' + data[key] + '&';

}

return params.substring(0, params.length - 1);

}

/**

* 设置请求的头信息

* @param {[type]} xhr [description]

* @param {[type]} headers [description]

*/

var setHeaders = function (xhr, headers){

if (typeof headers != "undefined") {

for (var key in headers) {

xhr.setRequestHeader(key, headers[key]);

}

}

}

/**

* 对外可访问方法

*/

return {

run : function (options){

var xhr = getXHR();

var opts = settings(options);

// 打开链接

xhr.open(opts.method, opts.url);

// 设置请求头 大专栏  跨域请求触发浏览器复杂请求span>

setHeaders(xhr, options.headers);

// 发送请求

xhr.send(opts.data);

// 设置响应成功后的处理

xhr.onreadystatechange = function (){

if (xhr.readyState == 4) {

if (xhr.status == 200) {

// console.log(xhr.responseText);

options.success(xhr.responseText);

}

}

}

}

}

})();

// 使用举例

ajax.run({

url : 'data.txt',

method : 'post',

data : {

"name" : "fantasy",

"age" : 12

},

headers : {

"Content-Type" : "application/json"

},

success : function (data){

console.log(data);

}

});

什么是跨域

页面发送一个ajax请求的时候

当前发送请求方叫做 Origin 叫做域 ,当请求一个资源的时候 资源的HOST就是他的域

比如我们在 baidu.com/login.html 页面请求 baidu.com/list.php 这个资源 这里的源 就是域名 www.baidu.com

如果请求其他的域名下的资源 www.360.com/corn.php 这个时候就存在跨域问题

具体的跨域情况如下:

如何跨域

如下图:

对象 XMLHttpRequest 报错了

请求是从域 http://www.webcors.dev/ 发送到 域 http://www.cors1.dev ,这是一个明显的跨域问题

但是看图我们可以看出来 其实这个请求已经发出去了,服务器也是将结果返回了,Content Download 这个是内容下载时间

但是浏览器并没有将这个内容显示给我们 也就是说这是浏览器中的安全机制

如何才能跨域 ? 接着看这个错误1No 'Access-Control-Allow-Origin' header is present on the requested resource.

在响应中没有找到 Access-Control-Allow-Origin 这个响应头

这说明我们需要在服务端设置响应头, 浏览器通过这个 HTML5 中的相应头 来决定这个跨域请求的数据是否有权显示这个内容

其实跨域这块有几个地方是需要服务器添加响应头才能实现的,浏览器是需要通过读取响应头来决定是否显示的

Access-Control-Allow-Origin * 声名哪些源是允许跨域请求的 表示任何域都可以请求 你也可以指定一个允许的域名 只能指定一个不能写多个.baidu.com 这种的泛解析也是不行的 他是完全匹配

Access-Control-Allow-Headers Origin,Accept,... 声明哪些请求头是可以跨域请求的

Access-Control-Allow-Method GET,POST,HEAD 声明跨域请求允许的方法

Access-Control-Allow-Credentials true 跨域时候是否允许传递 cookie 当使用这个参数的时候 Access-Control-Allow-Origin 这个参数是不能设置成 * 的

服务端如何设置跨域

举例

apache httpd.conf1

2

3

4

5

6

7

8

Options FollowSymLinks

AllowOverride All

Require all granted

Header set Access-Control-Allow-Origin *

Header set Access-Control-Allow-Method GET,POST,HEAD

Header set Access-Control-Allow-Origin Origin,Content-Type,Accept,X-Requested-With

nginx http.conf

1

2

3

4

5location / {

add_header Access-Control-Allow-Origin *

add_header Access-Control-Allow-Method GET,POST,HEAD

add_header Access-Control-Allow-Origin Origin,Content-Type,Accept,X-Requested-With

}

复杂请求

在上面讲到的跨域请求问题,这样的背景下 有时候你会发现 你只发出去了一个请求 但是在

浏览器里面能看到发出去的却是两个 第一个是OPTIONS请求 第二个才是你要发送的

出现这个现象是浏览器的一个 简单请求 复杂请求 的一个判断,复杂请求模式下 浏览器在发送请求前先

发送一个 OPTIONS 形式的 预请求 , 后面才会发送真正的请求

浏览器是如何来区分 是 复杂请求 还是 简单请求的呢?

简单请求:

HTTP请求方式是 下列的一种1

2

3HEAD

GET

POST

HTTP请求头仅包含下列选项1

2

3

4

5

6

7

8

9Accept

Accept-Language

Content-Language

Last-Event-ID

Content-Type

Content-Type 的值只能是下列的一种

application/x-www-form-urlencoded

multipart/form-data

text/plain

任何不满足上面要求的都会被当做复杂请求

举例如下1

2

3

4

5

6

7

8

9

10

11var url = "http://www.cors1.dev";

ajax.run({

url : url,

method : 'get',

headers : {

"Content-Type" : "application/json"

},

success : function (data){

console.log(data);

}

});

虽然是 GET 请求但是 在请求头的 Content-Type 设置的并不是规定的三个的之一

浏览器会当作复杂请求来处理

angularjs 如何设置 Content-Type

angularjs 如何发送一个ajax请求

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

  • {{x.id + ' ' + x.name}}

var url = "http://newbijia.work.dev/getBrand?type=wap";

var app = angular.module('app', []);

var data ={};

app.controller('demoController', function ($scope, $http){

app.config(function ($httpProvider) {

$httpProvider.defaults.headers.post = {}

});

});

$http({

method : "POST",

url : url,

headers : {

"Accept" : "test",

"Content-Type" : "application/json",

},

data : data

});

angularjs 里面可以设置 请求头

其中 如果没设置 data数据的情况下 头信息设置 Content-Type 无效

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值