这里讲的是不刷新页面的三种方式:
方式一:xmlrequest,也即原生方式
<input id="k1" name="k1">
<input type="submit" onclick="nativeSubmit()" id="submit">
<script>
function nativeSubmit() {
var k1_v=document.getElementById("k1").value
var data={'k1':k1_v}
data=JSON.stringify(data)
var xhr_obj=new XMLHttpRequest()
xhr_obj.open("post","/test")
xhr_obj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); //request.body
xhr_obj.send(data)
xhr_obj.onreadystatechange=function () {
if (xhr_obj.readyState == 4 && xhr_obj.status == 200) {
alert(xhr_obj.responseText);
}
}
}
</script>
表单处理过程:收集数据-->发送数据-->接收数据处理
原生方式中,通过选择器收集标签的取值,在open函数中指定提交的方式和目标url,在send中发送post请求的数据(如果用get,则在open里面的url部分用?k=v的形式发送),回调函数则通过触发onreadystatechange事件在执行,readyState有多个值,对应数据处理的不同阶段,当等于4时则表示数据接收完毕
这里加了个:xhr_obj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); //request.body
这里因为post请求默认放在body里面,只有加上这个头部,django才会把body的数据处理放到request.POST里面,ajax处理会有这部分,所以这里也设置
方式二:ajax
<input id="k1" name="k1">
<input type="submit" id="submit">
<script src="/static/js/jquery-3.5.1.min.js"> </script>
<script>
$("#submit").click(function () {
var k1_v=$("#k1").val()
var data={'k1':k1_v}
$.ajax({
type:"POST",
url:"/test",
data:data,
success(arg){
alert(arg)
}
})
})
</script>
ajax封装了原生的语法,使用更简单,缺点就是需要额外加载jquery文件,对于一些流量紧张的应用不适用
方式三:form+iframe标签
<iframe id="ifr" name="iframe" style="display: none"></iframe>
<form action="/test" method="POST" target="iframe">
<input id="k1" name="k1" >
<input type="submit" onclick="ifr1()" id="submit">
</form>
<script>
function ifr1(){
document.getElementById("ifr").onload=reload;
}
{# 这里为什么不直接在iframe标签那里绑定reload事件呢?#}
{# 因为会报错,如果iframe放在script上面会报reload函数找不到,如果放在下面则document找不到 #}
{# 这是iframe的特殊之处,原因待查明 #}
function reload() {
var content = this.contentWindow.document.body.innerHTML;
alert(content)
}
</script>
form表单通过target(值即iframe的name的值)与iframe关联,参数的设定跟直接form表单提交一样,差别在于回调函数的返回值在iframe里面,iframe类似一个小Windows对象,值放在document的body里面
这里<input type="submit" onclick="ifr1()" id="submit">,click事件处理在submit之前,所以可以直接这么写
前面的例子都是对字符串进行处理,若需要对文件进行处理,则可以用FormData对象进行封装
<input id="k1" type="file" name="k1">
<input type="submit" onclick="nativeSubmit()" id="submit">
<script>
function nativeSubmit() {
var k1_v=document.getElementById("k1").files[0]
console.log(k1_v)
var data=new FormData()
data.append("k1",k1_v)
var xhr_obj=new XMLHttpRequest()
xhr_obj.open("post","/test")
xhr_obj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); //request.body
xhr_obj.send(data)
xhr_obj.onreadystatechange=function () {
if (xhr_obj.readyState == 4 && xhr_obj.status == 200) {
alert(xhr_obj.responseText);
}
}
}
</script>
debug:
1.Refused to display 'http://127.0.0.1:8000/test' in a frame because it set 'X-Frame-Options' to 'deny'.
原因:现代浏览器采用X-Frame-Options HTTP标头,该标头指示是否允许在框架或iframe中加载资源。如果响应包含标头值为的标头,SAMEORIGIN则浏览器将仅在请求源自同一站点的情况下将资源加载到框架中。如果将标头设置为,DENY则无论哪个站点发出请求,浏览器都将阻止资源加载到框架中。
解决方法有以下三种:
<1>注销掉
'django.middleware.clickjacking.XFrameOptionsMiddleware'中间件
<2>处理函数前加上装饰器:
from django.views.decorators.clickjacking import xframe_options_exempt
@xframe_options_exempt
<3>在setting中设置:
X_FRAME_OPTIONS = 'SAMEORIGIN'
2.jsonp和cors头部实现跨域
问题:当form提交请求时,有同源限制,比如我的网站是a.com,我提交请求也是向a.com提交,当我向b.com提交请求的的时候,因为浏览器会判断同源限制,会导致收到的数据不显示
例子:
<button onclick="getvalue()">点击获取值</button>
返回值是:<input id="k1" name="k1">
<script src="/static/js/jquery-3.5.1.min.js"> </script>
<script>
function getvalue() {
$.ajax({
url:"http://127.0.0.1:9000/test1",
type:"get",
success(arg) {
$("#k1").val(arg)
}
})
}
</script>
报错:
、
解决:
方式一:cors头部
最简单的是取消限制,服务端在响应请求的时候,在http头部加上:
Access-Control-Allow-Origin :*
客户端看到这个头部会取消同源限制
服务端代码:
def test1(request):
ret=HttpResponse("hello")
ret["Access-Control-Allow-Origin"]="*"
return ret
方式二:jsonp
jsonp的原理在于利用其它可以跨域的标签,比如<script>、<img>等标签的src属性不受同源限制,jsonp就是动态创建这些标签,取得值后删除
<img>的src获取到数据后会渲染成图片,而在img标签中似乎没法获取图片的值,所以这里我用<script>标签
<script>标签的src获取到数值会以js的方式处理,所以如果我们服务端返回一个在前端已经定义的函数执行形式,比如func(),那么当客户端收到返回值就会执行对应函数,也就达到了回调函数的功能
前端代码:
<button onclick="getvalue()">点击获取值</button>
返回值是:<input id="k1" name="k1">
<script>
var url="http://127.0.0.1:8000/test1"
function getvalue() {
var s_ele=document.createElement("script")
s_ele.src=url
document.body.appendChild(s_ele)
document.body.removeChild(s_ele)
}
function func(arg) {
document.getElementById('k1').value=arg
服务端代码:
def test1(request):
ret=HttpResponse("func('hello')")
ret["Content-Type"]="text/javascript"
return ret
ajax的前端代码则更为简单,只要在dataType赋值jsonp,ajax默认就会以jsonp的形式跨域取值,代码如下:
<button onclick="getvalue()">点击获取值</button>
返回值是:<input id="k1" name="k1">
<script src="/static/js/jquery-3.5.1.min.js"> </script>
<script>
function getvalue() {
$.ajax({
url:"http://127.0.0.1:8000/test1",
dataType:"jsonp"
})
}
function func(arg) {
$("#k1").val(arg)
}
</script>
debug:
1.test:1 Refused to execute script from 'http://127.0.0.1:8000/test1' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
解决:HttpResponse返回设置头部:Content-Type;"text/javascript"