搜索 | 用户支持

防范以用户支持为名的诈骗。我们绝对不会要求您拨打电话或发送短信,及提供任何个人信息。请使用“举报滥用”选项报告涉及违规的行为。

详细了解

Cross-origin resource sharing (CORS) does not work in Firefox 13.0.1 or 6.0.2

more options

I have a simple Java HttpServlet and a simple JSP page. They are both served by a WebSphere Application Server at port 80 on my local host. I have created a TCP/IP Monitor at port 8081 in Eclipse IDE so as to create a second origin. The protocol output further down comes from this monitor. This should work equally well on a simple Tomcat server.

When I perform the cross-origin resource sharing test, I see that all of the correct TCP data is exchanged between Firefox and the web server (i.e. HTTP OPTIONS and its response followed by an HTTP POST and its response) but the data in the body of the POST response is never passed to the XMLHttpRequest javascript object's responseText or responseXML variables and I get a status equal to 0. If I click the button while pressing the keyboard control key then the test will work as it will not be performed as a cross-origin request.

Here are all of the files used in this test:

Servlet Cors.java

--------------------------------------------------------------------------------------

package example.cors;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class Cors
 */
public class Cors extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private static final String APPLICATION_XML_VALUE = "application/xml";

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doPost(request, response); // do the same as on the post
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setBufferSize(1024);
		response.setContentType(APPLICATION_XML_VALUE);
		response.setStatus(HttpServletResponse.SC_OK);
		String xml="<?xml version=\"1.0\"?>\n<hello>This is a wrapped message</hello>";
		response.setContentLength(xml.length());
		response.getWriter().append(xml);
		response.getWriter().close();
	}

	/**
	 * @see HttpServlet#doOptions(HttpServletRequest, HttpServletResponse)
	 */
	@SuppressWarnings("unchecked")
	protected void doOptions(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		Enumeration<String> headers=request.getHeaders("Origin");
		StringBuffer sb=new StringBuffer();
		while (headers.hasMoreElements()) {
			String o=headers.nextElement();
			if (sb.length()!=0) sb.append(", ");
			System.err.println("Origin= "+o);
			sb.append(o);
		}
		response.addHeader("Access-Control-Allow-Origin", sb.toString());
		response.addHeader("Access-Control-Allow-Methods","POST, GET, OPTIONS");
		sb=new StringBuffer();
		headers=request.getHeaders("Access-Control-Request-Headers");
		while (headers.hasMoreElements()) {
			String o=headers.nextElement();
			if (sb.length()!=0) sb.append(", ");
			System.err.println("Access-Control-Request-Headers= "+o);
			sb.append(o);
		}
		response.addHeader("Access-Control-Allow-Headers", sb.toString().toUpperCase());
		response.addHeader("Access-Control-Max-Age", Integer.toString(60*60)); // 1 hour
		response.addHeader("Content-Type","text/plain");
		response.addHeader("Allow", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS");
		response.getWriter().print("");
	}

}

--------------------------------------------------------------------------------------

And a simple JSP page test.jsp:

--------------------------------------------------------------------------------------
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<%
String url     ="http://localhost:8081/cors/ping";
String url_ctrl="http://localhost/cors/ping";
%>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Test CORS</title>
<script type="text/javascript">
var invocation; 
var method='POST'; 
var body = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><hello>Today</hello>";  
var buttontest2_label="Direct AJAX call";
      
function callOtherDomain(event){ 
  invocation = new XMLHttpRequest();
  if(invocation) {  
        var resultNode = document.getElementById("buttonResultNode");
        var resultMessage = document.getElementById("buttonMessageNode");
        resultNode.innerHTML = "";
        document.getElementById("buttontest2").value="Waiting response...";
        var url
        if (event.ctrlKey) url="<%=url_ctrl%>";
        else url="<%=url%>";
        resultMessage.innerHTML = "Sending "+method+" to URL: "+url;
      invocation.open(method, url, true);
//      invocation.withCredentials = "true";  
      invocation.setRequestHeader('X-PINGOTHER', 'pingpong');  
      invocation.setRequestHeader('Content-Type', 'application/xml'); 
      invocation.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); 
      invocation.onerror = function(errorObject) {
      	display_progress(resultMessage, "***** error occured=" +errorObject);
      }; 
      invocation.onreadystatechange = function() {
      		display_progress(resultMessage, "onreadystatechange="+invocation.readyState+", status="+invocation.status+", statusText="+invocation.statusText);
    		if(invocation.readyState == 4){
    			document.getElementById("buttontest2").value=buttontest2_label;
    			display_progress(resultMessage, "responseText="+invocation.responseText);
                resultNode.innerHTML = "Response from web service='"+invocation.responseText+"'";
    		}
      };  
      invocation.send(body);   
    }  
}
function display_progress(node, message) {
	node.innerHTML = node.innerHTML + "<br>" + message;
}
</script>
</head>
<body>
<p>The button will create a cross site request (Use the control key to disable this, i.e. no cross site request)</p>
<p><input type="button" id="buttontest2" onclick="callOtherDomain(event)" name="buttontest2" value="Waiting for page load..."></p>
<p id="buttonMessageNode"></p>
<p id="buttonResultNode"></p>
<script type="text/javascript">
document.getElementById("buttontest2").value=buttontest2_label;
</script>
</body>
</html>
--------------------------------------------------------------------------------------

When I click on the Direct AJAX call button, I get the following output on my page:

--------------------------------------------------------------------------------------

The button will create a cross site request (Use the control key to disable this, i.e. no cross site request)

Sending POST to URL: http://localhost:8081/cors/ping
onreadystatechange=2, status=0, statusText=
onreadystatechange=4, status=0, statusText=
responseText=
***** error occured=[object ProgressEvent]

Response from web service=''

--------------------------------------------------------------------------------------

Here is the HTTP traffic produced:

--------------------------------------------------------------------------------------
HTTP REQUEST
--------------------------------------------------------------------------------------
OPTIONS /cors/ping HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:13.0) Gecko/20100101 Firefox/13.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Origin: http://localhost
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,x-pingother,x-requested-with
Pragma: no-cache
Cache-Control: no-cache

POST /cors/ping HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:13.0) Gecko/20100101 Firefox/13.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
X-PINGOTHER: pingpong
Content-Type: application/xml; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: http://localhost/cors/client/test.jsp
Content-Length: 75
Origin: http://localhost
Pragma: no-cache
Cache-Control: no-cache

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><hello>Today</hello>
--------------------------------------------------------------------------------------
HTTP RESPONSE
--------------------------------------------------------------------------------------
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: CONTENT-TYPE,X-PINGOTHER,X-REQUESTED-WITH
Access-Control-Max-Age: 3600
Content-Type: text/plain;charset=ISO-8859-1
Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS
Content-Language: en-CA
Content-Length: 0
Date: Wed, 11 Jul 2012 17:50:10 GMT
Server: WebSphere Application Server/7.0

HTTP/1.1 200 OK
Content-Type: application/xml
Content-Length: 62
Content-Language: en-CA
Date: Wed, 11 Jul 2012 17:50:10 GMT
Server: WebSphere Application Server/7.0

<?xml version="1.0"?>
<hello>This is a wrapped message</hello>
--------------------------------------------------------------------------------------
I have a simple Java HttpServlet and a simple JSP page. They are both served by a WebSphere Application Server at port 80 on my local host. I have created a TCP/IP Monitor at port 8081 in Eclipse IDE so as to create a second origin. The protocol output further down comes from this monitor. This should work equally well on a simple Tomcat server. When I perform the cross-origin resource sharing test, I see that all of the correct TCP data is exchanged between Firefox and the web server (i.e. HTTP OPTIONS and its response followed by an HTTP POST and its response) but the data in the body of the POST response is never passed to the XMLHttpRequest javascript object's responseText or responseXML variables and I get a status equal to 0. If I click the button while pressing the keyboard control key then the test will work as it will not be performed as a cross-origin request. Here are all of the files used in this test: Servlet Cors.java <pre><nowiki>-------------------------------------------------------------------------------------- package example.cors; import java.io.IOException; import java.util.Enumeration; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class Cors */ public class Cors extends HttpServlet { private static final long serialVersionUID = 1L; private static final String APPLICATION_XML_VALUE = "application/xml"; /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); // do the same as on the post } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setBufferSize(1024); response.setContentType(APPLICATION_XML_VALUE); response.setStatus(HttpServletResponse.SC_OK); String xml="<?xml version=\"1.0\"?>\n<hello>This is a wrapped message</hello>"; response.setContentLength(xml.length()); response.getWriter().append(xml); response.getWriter().close(); } /** * @see HttpServlet#doOptions(HttpServletRequest, HttpServletResponse) */ @SuppressWarnings("unchecked") protected void doOptions(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Enumeration<String> headers=request.getHeaders("Origin"); StringBuffer sb=new StringBuffer(); while (headers.hasMoreElements()) { String o=headers.nextElement(); if (sb.length()!=0) sb.append(", "); System.err.println("Origin= "+o); sb.append(o); } response.addHeader("Access-Control-Allow-Origin", sb.toString()); response.addHeader("Access-Control-Allow-Methods","POST, GET, OPTIONS"); sb=new StringBuffer(); headers=request.getHeaders("Access-Control-Request-Headers"); while (headers.hasMoreElements()) { String o=headers.nextElement(); if (sb.length()!=0) sb.append(", "); System.err.println("Access-Control-Request-Headers= "+o); sb.append(o); } response.addHeader("Access-Control-Allow-Headers", sb.toString().toUpperCase()); response.addHeader("Access-Control-Max-Age", Integer.toString(60*60)); // 1 hour response.addHeader("Content-Type","text/plain"); response.addHeader("Allow", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS"); response.getWriter().print(""); } } -------------------------------------------------------------------------------------- And a simple JSP page test.jsp: -------------------------------------------------------------------------------------- <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <% String url ="http://localhost:8081/cors/ping"; String url_ctrl="http://localhost/cors/ping"; %> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Test CORS</title> <script type="text/javascript"> var invocation; var method='POST'; var body = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><hello>Today</hello>"; var buttontest2_label="Direct AJAX call"; function callOtherDomain(event){ invocation = new XMLHttpRequest(); if(invocation) { var resultNode = document.getElementById("buttonResultNode"); var resultMessage = document.getElementById("buttonMessageNode"); resultNode.innerHTML = ""; document.getElementById("buttontest2").value="Waiting response..."; var url if (event.ctrlKey) url="<%=url_ctrl%>"; else url="<%=url%>"; resultMessage.innerHTML = "Sending "+method+" to URL: "+url; invocation.open(method, url, true); // invocation.withCredentials = "true"; invocation.setRequestHeader('X-PINGOTHER', 'pingpong'); invocation.setRequestHeader('Content-Type', 'application/xml'); invocation.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); invocation.onerror = function(errorObject) { display_progress(resultMessage, "***** error occured=" +errorObject); }; invocation.onreadystatechange = function() { display_progress(resultMessage, "onreadystatechange="+invocation.readyState+", status="+invocation.status+", statusText="+invocation.statusText); if(invocation.readyState == 4){ document.getElementById("buttontest2").value=buttontest2_label; display_progress(resultMessage, "responseText="+invocation.responseText); resultNode.innerHTML = "Response from web service='"+invocation.responseText+"'"; } }; invocation.send(body); } } function display_progress(node, message) { node.innerHTML = node.innerHTML + "<br>" + message; } </script> </head> <body> <p>The button will create a cross site request (Use the control key to disable this, i.e. no cross site request)</p> <p><input type="button" id="buttontest2" onclick="callOtherDomain(event)" name="buttontest2" value="Waiting for page load..."></p> <p id="buttonMessageNode"></p> <p id="buttonResultNode"></p> <script type="text/javascript"> document.getElementById("buttontest2").value=buttontest2_label; </script> </body> </html> -------------------------------------------------------------------------------------- When I click on the Direct AJAX call button, I get the following output on my page: -------------------------------------------------------------------------------------- The button will create a cross site request (Use the control key to disable this, i.e. no cross site request) Sending POST to URL: http://localhost:8081/cors/ping onreadystatechange=2, status=0, statusText= onreadystatechange=4, status=0, statusText= responseText= ***** error occured=[object ProgressEvent] Response from web service='' -------------------------------------------------------------------------------------- Here is the HTTP traffic produced: -------------------------------------------------------------------------------------- HTTP REQUEST -------------------------------------------------------------------------------------- OPTIONS /cors/ping HTTP/1.1 Host: localhost:8081 User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:13.0) Gecko/20100101 Firefox/13.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Origin: http://localhost Access-Control-Request-Method: POST Access-Control-Request-Headers: content-type,x-pingother,x-requested-with Pragma: no-cache Cache-Control: no-cache POST /cors/ping HTTP/1.1 Host: localhost:8081 User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:13.0) Gecko/20100101 Firefox/13.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive X-PINGOTHER: pingpong Content-Type: application/xml; charset=UTF-8 X-Requested-With: XMLHttpRequest Referer: http://localhost/cors/client/test.jsp Content-Length: 75 Origin: http://localhost Pragma: no-cache Cache-Control: no-cache <?xml version="1.0" encoding="UTF-8" standalone="yes"?><hello>Today</hello> -------------------------------------------------------------------------------------- HTTP RESPONSE -------------------------------------------------------------------------------------- HTTP/1.1 200 OK Access-Control-Allow-Origin: http://localhost Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: CONTENT-TYPE,X-PINGOTHER,X-REQUESTED-WITH Access-Control-Max-Age: 3600 Content-Type: text/plain;charset=ISO-8859-1 Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS Content-Language: en-CA Content-Length: 0 Date: Wed, 11 Jul 2012 17:50:10 GMT Server: WebSphere Application Server/7.0 HTTP/1.1 200 OK Content-Type: application/xml Content-Length: 62 Content-Language: en-CA Date: Wed, 11 Jul 2012 17:50:10 GMT Server: WebSphere Application Server/7.0 <?xml version="1.0"?> <hello>This is a wrapped message</hello> --------------------------------------------------------------------------------------</nowiki></pre>

由cor-el于修改

所有回复 (6)

more options

Are there any relevant errors in Firefox's Error Console (Ctrl_Shift+j)?

Does it make any difference if you change this line to * (i.e., match any origin):


response.addHeader("Access-Control-Allow-Origin", "*");

Are you able to test on any other host, in case localhost is a special case?

more options

No errors in error console. No effect using *. I tried using the dns name of my localhost both in the Firefox URL and in the javascript and I get exactly the same. I have spent a huge amount of time looking into this issue.

One thing I noticed is that if I use the examples on the internet (http://arunranga.com/examples/access-control/preflightInvocation.html or http://saltybeagle.com/cors/) they work in the same browser. These examples however, are accessed through HTTP proxies.

I am wondering if the issue has to do with using the same hostname just with different ports.

more options

Jefferson, were you able to get my example to run. All you need is tomcat to run this test. Would you mind (or anyone else) mind trying my example out to see if you get the same result?

more options

It's unlikely I can replicate your environment in the near future (multiple ports on localhost; I don't think the server technology -- JSP, PHP, ASP -- is critical).

more options

I agree that the server technology is not important. However, my example is self contained. If you have eclipse you can use the tcp/ip monitor to provide the second port. Alternatively, you can configure tomcat to listen on two ports. Regardless of if you use my sample servlet or some other server technology, could you try to see if you can reproduce this?

Also, is there a way to report this as a Firefox bug which I strongly believe it is? If have done more tests using different configuration and I am unable to get it to work.

more options

Simpler test page (PHP): http://www.jeffersonscher.com/forumshots/corstest.html

I had to return the Access-Control-Allow-Origin header in the second response in order to get it to work. Try adding that to your doPost function (method?) and see whether that fixes it.