概述
跨域是指在同源策略限制下,客户端无法向不同源(协议、域名、端口)的服务器发送请求。但有些情况下需要跨域请求,这时可以使用以下几种方法:图片ping、JSONP和CORS。
方法一:图片ping
通过创建一个HTML的日志资源文件来达到跨域目的,将数据转化为图片地址,然后请求这个图片地址。
<img src="http://example.com/?data=[data]" />
这样发送是不会中止请求的,即使服务器不支持任何的输出形式。
优缺点:
- 优点:对浏览器兼容性要求较低,一般都可以完成跨域操作。
- 缺点:只能使用 GET 请求方式,并且无法设置请求头,只能从服务器拿到请求成功或失败的结果,且不能获得服务端返回的数据。
方法二:JSONP
JSONP 全称为 JSON with Padding,简单来说就是在js里面执行函数,为什么要用padding呢?因为 JSONP其实是利用<script>
标签来实现的,可以被普通的浏览器进行跨域访问的特性,这种格式的数据很难实现由 JSON 转译成 JSONP,因此使用了这种 hack 的方式。padding其实是指要在服务端将JSON数据填入到一对用户定义的函数调用中(函数名在URL中),从而构成JS文件(JSONP文件)。
假设客户端需要从 http://example.com/?callback=func
这个URL获取数据,并且要求接口返回的数据格式为 callback(data)
。
function func(data) {
console.log(data)
}
const script = document.createElement('script')
script.src = 'http://example.com/?callback=func'
document.head.append(script)
在这个js文件中,会向服务器发送一个 URL 请求,并且 URL 中包含一个名为callback
的参数,这个参数的值就是要获得 JSON 数据之后要立即调用的函数名,在服务器端将数据放进其中,并返回这个 js 文件内容,客户端浏览器接收到这个js文件之后,会自动执行func(data)
函数。
优缺点:
- 优点:能跨域请求跨域数据,不受同源策略限制,支持 GET 请求,可以向服务端发送请求时设置请求头。
- 缺点:只支持 GET 请求,并且必须判断响应的数据格式,需要服务端配合,且容易受到XSS攻击。
方法三:CORS
CORS 全称为 Cross-Origin Resource Sharing,是 HTML5 提供的一种机制,采用额外的 HTTP 头来告诉浏览器,以允许 Web 应用程序访问不属于其来源的选定资源,浏览器会对复杂请求(例如:get/post以及POST的两种Content-Type:application/json,application/x-www-form-urlencoded)发起一次预检,可以看做是一次请求前置确认,服务器返回“METHOD,Origin,Accept-language,Accept”等字段,携带带校验信息,让浏览器放行实际的请求。
在服务器端,需要添加如下响应头:
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Methods: POST,GET,OPTIONS
Access-Control-Max-Age: 1000
Access-Control-Allow-Headers: Content-Type, Authorization
在客户端,直接发送 AJAX 请求,浏览器会自动在请求头中添加Origin
字段发起预检请求,如果服务器支持跨域,会返回以上响应头信息。
const xhr = new XMLHttpRequest()
xhr.open('POST', 'http://example.com/api')
xhr.setRequestHeader('Content-Type', 'application/json')
xhr.setRequestHeader('Authorization', 'Bearer ' + token)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText)
}
}
xhr.send(JSON.stringify({data: 'some data'}))
优缺点:
- 优点:绝大多数浏览器都支持,以标准化的请求头、状态码、请求方法来对跨域请求和响应进行规范,同时支持 GET/POST 等请求方式。
- 缺点:需要服务器端进行配置,在某些第三方库中并不支持 CORS。
示例一
通过JSONP方式从服务器获取数据。
服务端随意设置一个接口,返回数据。
const express = require('express')
const app = express()
app.get('/jsonp', (req, res) => {
const callback = req.query.callback
const data = {a: 1, b: 2, c: 3}
res.send(`${callback}(${JSON.stringify(data)})`)
})
app.listen(3000, () => console.log('listening on port 3000'))
客户端通过JSONP跨域获取数据,代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JSONP Demo</title>
</head>
<body>
<script>
function handleData(data) {
console.log(data)
}
const script = document.createElement('script')
script.src = 'http://localhost:3000/jsonp?callback=handleData'
document.head.append(script)
</script>
</body>
</html>
示例二
通过CORS方式从服务器获取数据。
服务端随意设置一个接口,返回数据。
const express = require('express')
const app = express()
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Methods', 'GET,POST,OPTIONS')
res.header('Access-Control-Allow-Headers', 'Origin,Content-Type,Authorization')
next()
})
app.post('/cors', (req, res) => {
const data = req.body
res.json(data)
})
app.listen(3000, () => console.log('listening on port 3000'))
客户端通过 AJAX 跨域获取数据,代码如下所示:
const xhr = new XMLHttpRequest()
xhr.open('POST', 'http://localhost:3000/cors')
xhr.setRequestHeader('Content-Type', 'application/json')
xhr.setRequestHeader('Authorization', 'Bearer ' + token)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText)
}
}
xhr.send(JSON.stringify({data: 'some data'}))
结语
以上三种方法均可用于跨域请求,但不同的请求方式适用于不同的场景,需要根据实际业务情况选择。而若是自身网站项目,建议使用第三种CORS方式,若要集成第三方传输库则可考虑JSONP方式。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:js实现跨域的几种方法汇总(图片ping、JSONP和CORS) - Python技术站