【问题解决】XMLHttpRequest cannot load http://xxx.xxx No 'Access-Control-Allow-Origin'

本文介绍了两种解决Ajax跨域问题的方法:一是通过jsonp方式利用回调函数实现跨域数据交互;二是利用CORS Proxy进行请求转发,实现跨域访问。

问题描述:"XMLHttpRequest cannot load http://xxx.xxx. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8020' is therefore not allowed access."/xxx.html (0)

出现原因:ajax本身实际上是通过XMLHttpRequest对象来进行数据的交互,而浏览器处于安全考虑,不允许js代码进行跨域操作,所以会出现这个错误

解决方法:

方案一.一般jQuery解决跨域是通过jsonp的方式,添加callback=xxx,服务器返回xxx(...),这种方式需要服务器代码帮忙

举个栗子:在index.html中 

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
		<script type="text/javascript">
			$(function(){
				var url = "jsonp.php?num1=1&num2=2&callbackname=jsonp_callback"; //访问localhost下的jsonp.php
			    var scriptTag = document.createElement("script");   //创建一个script标签
			    scriptTag.setAttribute("src",url);  //设置script的src属性
			    document.body.appendChild(scriptTag);   //将script标签添加到body中
			   
			});
			 //回调函数
		    var jsonp_callback = function(resultObj){
		        $("#res").text(resultObj);
		    }
		</script>
	</head>
	<body>
		<p id="res"></p>
	</body>
</html>


jsonp.php

<?php 
$num1= $_GET["num1"];
$num2= $_GET["num2"];
$result = $num1 + $num2;
$callbackname = $_GET["callbackname"];    //回调函数名称
echo "$callbackname($result)";
?>
最终index.html中显示 3 

方案二.通过CORS(跨域资源共享) Proxy 对请求进行转发,就可以实现跨域访问。

如: 请求地址是 http://op.juhe.cn/onebox/weather/query?key=3611a1e75f91ff1544fc9f84ec489021&dtype=json&cityname=武汉

则修改为  跨域服务器地址/ http://op.juhe.cn/onebox/weather/query?key=3611a1e75f91ff1544fc9f84ec489021&dtype=json&cityname=武汉

(例如:http://proxy.e12e.com/? http://op.juhe.cn/onebox/weather/query?key=3611a1e75f91ff1544fc9f84ec489021&dtype=json&cityname=武汉)这样就可以很方便使用代理的方式来访问api接口了

<think> 我们遇到了一个典型的CORS(跨域资源共享)错误。这个错误发生在您尝试从源`http://192.168.88.1`发送请求到`http://192.168.8.1`时,因为目标服务器没有设置适当的CORS响应头。 ### CORS错误详解 当浏览器发送跨域请求时,会先发送一个OPTIONS预检请求(如果是复杂请求),然后目标服务器必须返回包含`Access-Control-Allow-Origin`头的响应,浏览器才会允许实际的请求。错误消息明确指出目标资源(192.168.8.1)没有设置这个头部。 ### 解决方案 #### 方案1:在目标服务器配置CORS(最佳方案) 在目标服务器(192.168.8.1)上添加响应头: ```nginx # Nginx配置示例 location / { add_header 'Access-Control-Allow-Origin' 'http://192.168.88.1'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; } ``` 或者允许任意来源(不推荐用于生产环境): ```nginx add_header 'Access-Control-Allow-Origin' '*'; ``` #### 方案2:使用代理绕过CORS(客户端不可控服务器时的解决方案) 建立同源代理,例如在您的Web服务器(192.168.88.1)上设置代理路由: ```javascript // Node.js Express代理示例 const express = require('express'); const request = require('request'); const app = express(); app.use('/proxy', (req, res) => { const targetURL = 'http://192.168.8.1' + req.url.replace('/proxy',''); req.pipe(request(targetURL)).pipe(res); }); ``` #### 方案3:修改请求模式(仅适用于简单请求) 如果请求是简单请求(GET/HEAD/POST,且仅包含简单头部),可以尝试: ```javascript xhr.withCredentials = false; // 默认值 // 或者使用 no-cors 模式(Fetch API) fetch('http://192.168.8.1/', { mode: 'no-cors' }); ``` 注意:`no-cors`模式会导致响应不透明(无法读取响应内容) #### 方案4:禁用浏览器安全策略(仅限本地开发) **仅用于测试**,启动浏览器时禁用安全策略: - Chrome (Windows): ```batch chrome.exe --disable-web-security --user-data-dir="C:/temp" ``` ### 针对XMLHttpRequest的修正代码 ```javascript // 尝试使用no-cors模式(但无法读取响应内容) var xhr = new XMLHttpRequest(); xhr.open('GET', testURL, true); xhr.timeout = 1500; // 不能设置withCredentials为true,除非服务器允许 xhr.withCredentials = false; xhr.onload = function() { //no-cors模式下,状态码始终为0,无法读取响应 console.log("请求完成(无法读取响应)"); }; xhr.onerror = function() { console.error("请求失败"); }; xhr.send(); ``` ### 推荐解决方案组合 1. **开发阶段**:使用浏览器禁用安全策略临时测试 2. **生产环境**: - 如果控制目标服务器 → 配置CORS头 - 否则 → 设置同源代理 §§相关问题§§ 1. 如何在Apache服务器上配置CORS头部以允许跨域请求? 2. 使用Fetch API时,no-cors模式有哪些具体限制? 3. 如何为POST请求配置CORS预检请求(Preflight)处理? 4. 当需要传递身份验证cookie时,如何正确设置withCredentials属性? 5. 有哪些工具可以实时监控和分析CORS预检请求的发送与响应过程? </think> ### CORS 错误原因及解决方案分析 您遇到的错误是典型的跨域资源共享(CORS)策略阻止问题。具体原因和解决方案如下: #### 错误原因详解 1. **同源策略违反**: - 当前页面来源:`http://192.168.88.1` - 请求目标:`http://192.168.8.1` - 浏览器阻止了不同源(协议+域名+端口)的请求 2. **缺少 CORS 响应头**: - 目标服务器 (`192.168.8.1`) 未返回必需的响应头: ```http Access-Control-Allow-Origin: http://192.168.88.1 Access-Control-Allow-Methods: GET ``` 3. **预检请求失败**: - 浏览器自动发送的 OPTIONS 预检请求未获正确响应 #### 完整的解决方案 ##### 方案1:在目标服务器配置 CORS(推荐) 在 `192.168.8.1` 的服务器配置中添加响应头: ```nginx # Nginx 配置示例 location / { add_header 'Access-Control-Allow-Origin' 'http://192.168.88.1'; add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS'; add_header 'Access-Control-Allow-Headers' '*'; add_header 'Access-Control-Max-Age' 86400; if ($request_method = 'OPTIONS') { return 204; } } ``` ##### 方案2:使用代理绕过 CORS(客户端解决方案) ```javascript // 在同源服务器上创建代理端点 const gatewayIP = "192.168.8.1"; const proxyURL = "/api/proxy"; // 同源地址 // 前端请求代码 fetch(proxyURL, { headers: { "X-Target-URL": `http://${gatewayIP}/` } }) ``` 后端 Node.js 代理示例: ```javascript const express = require('express'); const fetch = require('node-fetch'); const app = express(); app.get('/api/proxy', async (req, res) => { const targetURL = req.header('X-Target-URL'); try { const response = await fetch(targetURL); const data = await response.text(); res.send(data); } catch (e) { res.status(500).send("Proxy error"); } }); ``` ##### 方案3:修改客户端请求配置 ```javascript // 使用 no-cors 模式(但无法读取响应内容) fetch(`http://${gatewayIP}/`, { mode: 'no-cors' }); // 或者使用 JSONP(仅限 GET 请求) function handleResponse(data) { console.log("接收数据:", data); } const script = document.createElement('script'); script.src = `http://${gatewayIP}/?callback=handleResponse`; document.body.appendChild(script); ``` ##### 方案4:临时开发解决方案(不安全) ```bash # 启动 Chrome 时禁用安全策略(仅开发环境) google-chrome --disable-web-security --user-data-dir=/tmp/chrome-temp ``` ### 最佳实践建议 1. **客户端检测逻辑优化**: ```javascript // 先检查是否同源 if (new URL(testURL).origin === window.location.origin) { // 直接请求 } else { // 使用代理方案 } ``` 2. **错误处理增强**: ```javascript xhr.onerror = function() { if (xhr.status === 0) { console.error("CORS阻止或网络错误"); } }; ``` 3. **替代检测方案**: ```javascript // 使用图片ping检测设备可用性 function checkDevice(url) { return new Promise((resolve) => { const img = new Image(); img.onload = () => resolve(true); img.onerror = () => resolve(false); img.src = url + '?t=' + Date.now(); }); } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值