一、客户端
google浏览器
<!-- 引入jquery -->
<script src="http://libs.baidu.com/jquery/2.1.4/jquery.js"></script>
二、服务端
public class MyServer {
public static void main(String[] args) {
try {
openServer(8888);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void openServer(int port) throws IOException {
// 创建ServerSocket
ServerSocket serverSocket = new ServerSocket();
// 绑定端口
serverSocket.bind(new InetSocketAddress(port));
System.out.println("Server启动...");
while (true){
// 堵塞,等待客户端连接
Socket socket = serverSocket.accept();
BufferedReader br = null;
BufferedWriter bw = null;
try {
System.out.println("port " + socket.getPort() + " 连接成功...");
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
// 接受数据
StringBuilder reqMsg = new StringBuilder();
char[] buffer = new char[1024];
while (true) {
int count = br.read(buffer);
reqMsg.append(buffer, 0, count);
if (count < 1024) {
break;
}
}
if (reqMsg.length() > 0) {
System.out.println(String.format("- - - 接受数据长度: %s - - -", reqMsg.length()));
System.out.println(reqMsg.toString());
}
// 返回数据
// 设置允许跨域
StringBuilder respMsg = new StringBuilder();
respMsg.append("HTTP/1.1 200");
respMsg.append("n");
respMsg.append("Access-Control-Allow-Origin: *");
respMsg.append("n");
respMsg.append("Access-Control-Allow-Methods: GET,POST");
respMsg.append("n");
respMsg.append("Access-Control-Allow-Headers: content-type");
respMsg.append("n");
respMsg.append("Access-Control-Max-Age: 2");
bw.write(respMsg.toString());
System.out.println("port " + socket.getPort() + " 连接结束...");
System.out.println("- - - - - - - - - - - - - - - - - - - -");
} catch (Exception e) {
if (bw != null) {
bw.write("HTTP/1.1 404 ERROR:FILE NOT FINDED");
}
} finally {
if (bw != null) {
bw.close();
}
if (br != null) {
br.close();
}
if (socket != null) {
socket.close();
}
}
}
}
}
三、XMLHttpRequest
1.xhr发送get请求
代码:
function xhrForGet() {
var obj = {"username": "active pirate", "age": 18};
// $.param 把对象进行url编码
// username=active+pirate&age=18
var encodeObj = $.param(obj);
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://localhost:8888/hello?" + encodeObj);
// 设置请求头,可以设置任意值,XMLHttpRequest对content-type的值,没有限制校验,相当于直接写入一行数据
// 对于XMLHttpRequest,content-type与request body(请求体)没有关系
// xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
// send函数参数request body,GET请求没有request body
xhr.send();
xhr.onreadystatechange = function(){
//若响应完成
if(xhr.readyState === 4){
// 请求成功
if (xhr.status === 200) {
console.log("success");
} else {
console.log(xhr.status);
}
}
}
}
结果:
port 36052 连接成功...
- - - 接受数据长度: 458 - - -
GET /hello?username=active+pirate&age=18 HTTP/1.1
Host: localhost:8888
Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Accept: */*
Origin: http://localhost:63342
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:63342/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
port 36052 连接结束...
- - - - - - - - - - - - - - - - - - - -
2.xhr发送post请求
如果没有设置content-type, content-type会是text/plain
代码:
function xhrForPost2() {
var obj = {"username": "active pirate", "age": 18};
// $.param 把对象进行url编码
// username=active+pirate&age=18
var encodeObj = $.param(obj);
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://localhost:8888/hello");
// 设置request body,放入字符串
xhr.send(encodeObj);
xhr.onreadystatechange = function(){
//若响应完成
if(xhr.readyState === 4){
// 请求成功
if (xhr.status === 200) {
console.log("success");
} else {
console.log(xhr.status);
}
}
}
}
结果:
port 37316 连接成功...
- - - 接受数据长度: 518 - - -
POST /hello HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Content-Length: 29
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Content-Type: text/plain;charset=UTF-8
Accept: */*
Origin: http://localhost:63342
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:63342/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
username=active+pirate&age=18
port 37316 连接结束...
- - - - - - - - - - - - - - - - - - - -
3.xhr发送文件
xhr上传文件需要使用FormData对象
如果没有设置content-type, content-type会是multipart/form-data
代码:
<form id="myForm">
username: <input id="username" name="username" type="text"><br/>
age: <input id="age" name="age" type="text"><br/>
<input id="myfile" name="myfile" type="file"><br/>
<input type="button" value="ajax sumbmit" onclick="ajaxSubmit()"><br>
</form>
function xhrForPost3() {
var formData = new FormData();
formData.append("username", $('#username').val());
formData.append("age", $('#age').val());
formData.append("myfile", $("#myfile")[0].files[0]);
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://localhost:8888/hello");
// 设置request body,放入FormData对象
// 如果没有设置content-type, content-type会是multipart/form-data
xhr.send(formData);
xhr.onreadystatechange = function(){
//若响应完成
if(xhr.readyState === 4){
// 请求成功
if (xhr.status === 200) {
console.log("success");
} else {
console.log(xhr.status);
}
}
}
}
上传普通文件结果:
port 37800 连接成功...
- - - 接受数据长度: 925 - - -
POST /hello HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Content-Length: 391
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryk9AH5gOzWLTc09nL
Accept: */*
Origin: http://localhost:63342
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:63342/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
------WebKitFormBoundaryk9AH5gOzWLTc09nL
Content-Disposition: form-data; name="username"
active pirate
------WebKitFormBoundaryk9AH5gOzWLTc09nL
Content-Disposition: form-data; name="age"
18
------WebKitFormBoundaryk9AH5gOzWLTc09nL
Content-Disposition: form-data; name="myfile"; filename="a.txt"
Content-Type: text/plain
abcd
efgh
------WebKitFormBoundaryk9AH5gOzWLTc09nL--
port 37800 连接结束...
- - - - - - - - - - - - - - - - - - - -
上传图片结果:
port 38838 连接成功...
- - - 接受数据长度: 2164 - - -
POST /hello HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Content-Length: 1689
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarypAybx5xfLXDlKhqh
Accept: */*
Origin: http://localhost:63342
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:63342/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
------WebKitFormBoundarypAybx5xfLXDlKhqh
Content-Disposition: form-data; name="username"
active pirate
------WebKitFormBoundarypAybx5xfLXDlKhqh
Content-Disposition: form-data; name="age"
18
------WebKitFormBoundarypAybx5xfLXDlKhqh
Content-Disposition: form-data; name="myfile"; filename="mypic.png"
Content-Type: image/png
�PNG
�4�����&&��ffl�I"w���y��[^�Q�ǹ_3��ט���YYY.��2?�81��{r��D��� ���ٷ9�7l��o��s��$�Jw}!y�>���������
�4k'���o+�V1�����@��@Pp� ���5l{5�`P���P�GÊ&����s�aHX�+�cD�K�$�����u��F�u��``��%���)F�7��D�p���8;�W
�N7��c��cǾ� �_��z5�j���y��2����u� a���(
Z�)(��Z������;��H�%
>Z�[9ݥ n�%!(8��S'�X��&�M#u�����G
���(��a�](L��nc
��vq��vv9M���+��j���Q��9�y��� C�H�;ɩ�a�Y>����<*
�y&��Ӊ�#�$��v�RW�_�n"�� byz3�� �GCm3^Շ��@U{U�B��*���҈�i� �H��l�z�Kյ4�8q߾�ǫ':f:���X�L+�ͺ����� �6���`g IEND�B`�
------WebKitFormBoundarypAybx5xfLXDlKhqh--
port 38838 连接结束...
- - - - - - - - - - - - - - - - - - - -
四、AJAX
1.ajax发送get请求
常用的 AJAX 库,如 jQuery,内部已经封装了参数序列化(编码)的方法 (jquery.param)
.serialize()是jquery把表单编码的方法
指定data参数值是对象时,ajax内部会调用$.param(obj),转化为编码后的字符串
代码:
function ajaxForGet() {
var obj = {"username": "active pirate", "age": 18};
// 指定data参数值是对象时,ajax内部会调用$.param(obj),转化为编码后的字符串
$.ajax({
type: "GET",
url: "http://localhost:8888/hello" ,
data: obj,
success: function (result) {
console.log(result);
},
error : function(err) {
console.log(err);
}
});
}
结果:
port 55260 连接成功...
- - - 接受数据长度: 458 - - -
GET /hello?username=active+pirate&age=18 HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Accept: */*
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Origin: http://localhost:63342
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:63342/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
port 55260 连接结束...
- - - - - - - - - - - - - - - - - - - -
2.ajax发送post请求
如果没有指定contentType,传送给服务端的Content-Type是application/x-www-form-urlencoded
如果指定contentType: false,传送给服务端的Content-Type: text/plain
代码:
function ajaxForPost2() {
var obj = {"username": "active pirate", "age": 18};
// 指定data参数值是对象时,ajax内部会调用$.param(obj),转化为编码后的字符串
$.ajax({
type: "POST",
url: "http://localhost:8888/hello" ,
data: obj,
success: function (result) {
console.log(result);
},
error : function(err) {
console.log(err);
}
});
}
结果:
port 57082 连接成功...
- - - 接受数据长度: 542 - - -
POST /hello HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Content-Length: 29
Accept: */*
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://localhost:63342
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:63342/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
username=active+pirate&age=18
port 57082 连接结束...
- - - - - - - - - - - - - - - - - - - -
3.ajax上传文件
processData: false 表示不对data参数进行编码
如果没有指定contentType,传送给服务端的Content-Type是application/x-www-form-urlencoded
如果指定contentType: false,传送给服务端的Content-Type: multipart/form-data
代码:
<form id="myForm">
username: <input id="username" name="username" type="text"><br/>
age: <input id="age" name="age" type="text"><br/>
<input id="myfile" name="myfile" type="file"><br/>
<input type="button" value="ajax sumbmit" onclick="ajaxSubmit()"><br>
</form>
function ajaxForPost3() {
var formData = new FormData();
formData.append("username", $('#username').val());
formData.append("age", $('#age').val());
formData.append("myfile", $("#myfile")[0].files[0]);
$.ajax({
type: "POST",
url: "http://localhost:8888/hello" ,
data: formData,
processData: false,
contentType: false,
success: function (result) {
console.log(result);
},
error : function(err) {
console.log(err);
}
});
}
上传普通文件结果:
port 36814 连接成功...
- - - 接受数据长度: 925 - - -
POST /hello HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Content-Length: 391
Accept: */*
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryKADGPVYcZgoFO0dn
Origin: http://localhost:63342
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:63342/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
------WebKitFormBoundaryKADGPVYcZgoFO0dn
Content-Disposition: form-data; name="username"
active pirate
------WebKitFormBoundaryKADGPVYcZgoFO0dn
Content-Disposition: form-data; name="age"
18
------WebKitFormBoundaryKADGPVYcZgoFO0dn
Content-Disposition: form-data; name="myfile"; filename="a.txt"
Content-Type: text/plain
abcd
efgh
------WebKitFormBoundaryKADGPVYcZgoFO0dn--
port 36814 连接结束...
- - - - - - - - - - - - - - - - - - - -
上传图片结果:
port 37442 连接成功...
- - - 接受数据长度: 2164 - - -
POST /hello HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Content-Length: 1689
Accept: */*
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryAS0m2a4NFg2AvWTJ
Origin: http://localhost:63342
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:63342/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
------WebKitFormBoundaryAS0m2a4NFg2AvWTJ
Content-Disposition: form-data; name="username"
active pirate
------WebKitFormBoundaryAS0m2a4NFg2AvWTJ
Content-Disposition: form-data; name="age"
18
------WebKitFormBoundaryAS0m2a4NFg2AvWTJ
Content-Disposition: form-data; name="myfile"; filename="mypic.png"
Content-Type: image/png
�PNG
�4�����&&��ffl�I"w���y��[^�Q�ǹ_3��ט���YYY.��2?�81��{r��D��� ���ٷ9�7l��o��s��$�Jw}!y�>���������
�4k'���o+�V1�����@��@Pp� ���5l{5�`P���P�GÊ&����s�aHX�+�cD�K�$�����u��F�u��``��%���)F�7��D�p���8;�W
�N7��c��cǾ� �_��z5�j���y��2����u� a���(
Z�)(��Z������;��H�%
>Z�[9ݥ n�%!(8��S'�X��&�M#u�����G
���(��a�](L��nc
��vq��vv9M���+��j���Q��9�y��� C�H�;ɩ�a�Y>����<*
�y&��Ӊ�#�$��v�RW�_�n"�� byz3�� �GCm3^Շ��@U{U�B��*���҈�i� �H��l�z�Kյ4�8q߾�ǫ':f:���X�L+�ͺ����� �6���`g IEND�B`�
------WebKitFormBoundaryAS0m2a4NFg2AvWTJ--
port 37442 连接结束...
- - - - - - - - - - - - - - - - - - - -
五、跨域
当一个请求url的协议、域名、端口三者之间的任意一个与当前页面url不同即为跨域
跨域请求虽然会被浏览器拦截下来,但拦截的是响应(Response)而不是请求(Request)
AJAX请求是由XMLHttpRequest对象实现的,而XMLHttpRequest遵守同源策略(same-origin policy)。
如果要跨域请求,此时需要遵守CORS(Cross-Origin Resource Sharing) (跨域资源共享)机制。
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)
非普通请求在发送请求前,会发送一个方法为OPTIONS的预请求(preflighted request)
以下三种情况会发送OPTIONS的预请求(preflighted request):
- 请求方法不是GET/HEAD/POST
- POST请求的Content-Type并非application/x-www-form-urlencoded, multipart/form-data, 或text/plain
- 请求设置了自定义的header字段
对于普通跨域请求:
设置响应头Access-Control-Allow-Origin: *
对于非普通跨域请求:
设置允许域的方法:
Access-Control-Allow-Methods: GET,POST
设置允许跨域的请求头:
Access-Control-Allow-Headers: content-type
六、SpringBoot 解决跨域
设置 ExposedHeader,允许 js 得到的响应头信息
1.配置 CORS
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 所有接口
.allowCredentials(true) // 是否发送 Cookie
.allowedOrigins("*") // 支持域
.allowedMethods("GET", "POST", "PUT", "DELETE") // 支持方法
// .exposedHeaders("token")
.allowedHeaders("*");
}
}
2.CorsFilter
@Configuration
public class BeanConfig {
@Bean
public CorsFilter corsFilter() {
// 1.创建 CORS 配置对象
CorsConfiguration config = new CorsConfiguration();
// 支持域
config.addAllowedOrigin("*");
// 是否发送 Cookie
config.setAllowCredentials(true);
// 支持请求方式
config.addAllowedMethod("*");
// 允许的原始请求头部信息
config.addAllowedHeader("*");
// 暴露的头部信息
// config.addExposedHeader("token");
// 2.添加地址映射
UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
corsConfigurationSource.registerCorsConfiguration("/**", config);
// 3.返回 CorsFilter 对象
return new CorsFilter(corsConfigurationSource);
}
}
3.CrossOrigin 注解
@RestController
@CrossOrigin
public class CrossController {
@GetMapping("/cross")
public String cross() {
return "success";
}
}