AndroidAsync icon indicating copy to clipboard operation
AndroidAsync copied to clipboard

setup server to response to CORS `OPTIONS` request

Open futurist opened this issue 6 years ago • 2 comments

How to make Async-Server to response below HTTP headers:

OPTIONS http://localhost:3048/Token HTTP/1.1
Host: localhost:3048
Connection: keep-alive
Access-Control-Request-Method: POST
Access-Control-Request-Headers: accept, authorization, content-type
Accept: */*
Origin: http://localhost:2757
Referer: http://localhost:2757/Auth/login
... ...

This is the chrome Preflight OPTIONS request header, how to setup server to response to this OPTIONS request?

futurist avatar Nov 25 '17 02:11 futurist

I've found the solution, as below:


void setResponseHeaders(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
		Headers allHeaders = response.getHeaders();
		Headers reqHeaders = request.getHeaders();

		String corsHeaders = reqHeaders.get("access-control-request-headers");

		if(corsHeaders!=null) {
			// common headers
			allHeaders.set("Access-Control-Allow-Origin", "*");
			allHeaders.set("Access-Control-Allow-Credentials", "true");
			allHeaders.set("Access-Control-Allow-Headers", corsHeaders);
			allHeaders.set("Access-Control-Allow-Methods", "HEAD,OPTIONS,GET,POST,PUT,PATCH,DELETE,CONNECT");
			allHeaders.set("Access-Control-Max-Age", "86400");
		}
}

... ...

	server.addAction("OPTIONS",".+", new HttpServerRequestCallback() {
		@Override
		public void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {

			setResponseHeaders(request, response, false);
			response.send("ok");
		}
	});

Just tested seems worked here.

futurist avatar Nov 25 '17 04:11 futurist

Two big images for showing a successful demo: image image

I took a whole night to fix this issue. Now the code followed works for Chrome and Axios with/without Cookie for GET, POST application/json, POST www-form-url-encoded and POST form-data:

private void startServer(int port) {
    server.addAction("OPTIONS", "[\\d\\D]*", this); //add OPTIONS
    // server.get("[\\d\\D]*", this);
    // server.post("[\\d\\D]*", this);
    server.get("/", this);
    server.post("/method/list", this);
    server.post("/method/invoke", this);
    server.listen(mAsyncServer, port);
}

@Override
public void onRequest(final AsyncHttpServerRequest asyncHttpServerRequest, final AsyncHttpServerResponse asyncHttpServerResponse) {
    Headers allHeaders = asyncHttpServerResponse.getHeaders();
    Headers reqHeaders = asyncHttpServerRequest.getHeaders();

    String corsHeaders = reqHeaders.get("access-control-request-headers");
    String corsMethod = reqHeaders.get("access-control-request-method");

    String origin = reqHeaders.get("origin");
    String cookie = reqHeaders.get("cookie");

    //Access-Control-Allow-Credentials: true  is conflict with  Access-Control-Allow-Origin: * , you need to put origin value
    allHeaders.set("Access-Control-Allow-Origin", TextUtils.isEmpty(origin) ? "*" : origin);
    allHeaders.set("Access-Control-Allow-Credentials", "true");
    allHeaders.set("Access-Control-Allow-Headers", TextUtils.isEmpty(corsHeaders) ? "*" : corsHeaders);
    allHeaders.set("Access-Control-Allow-Methods", TextUtils.isEmpty(corsMethod) ? "*" : corsMethod);
    allHeaders.set("Access-Control-Max-Age", "86400");
    
    if (TextUtils.isEmpty(cookie) == false) {
        allHeaders.set("Set-Cookie", cookie + System.currentTimeMillis());
    }

    if ("OPTIONS".toLowerCase().equals(asyncHttpServerRequest.getMethod().toLowerCase())) {
        asyncHttpServerResponse.send("application/json; charset=utf-8", "{}");
        return;
    }

    //TODO

}

Other browsers and http libraries haven't been tested yet, but most of them should pass the tests.

see the complete file by the link followed: https://github.com/APIJSON/APIJSON/blob/master/APIJSON-Android/APIJSONTest/app/src/main/java/apijson/demo/ui/UnitActivity.java

If there is anything wrong, please reply me, thank you~

TommyLemon avatar Jul 12 '20 16:07 TommyLemon