在 http 请求中使用 CORS

Posted

技术标签:

【中文标题】在 http 请求中使用 CORS【英文标题】:Use CORS in a http request 【发布时间】:2018-03-05 14:39:07 【问题描述】:

今天,我有以下问题。我想向 rest api 发出 http 请求,但我只收到 405 错误。我搜索并发现,api使用cors。 那么如何使用 cors 发出 http 请求呢?

这是我的 http 客户端:

package community.opencode.minetools4j.util.http;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NonNull;
import org.apache.commons.io.IOUtils;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * This is an utility class.
 * It simplify making HTTP requests
 */
public class HttpRequest 

    /**
     * Performs a new HTTP request
     *
     * @param requestBuilder See @link RequestBuilder
     * @return See @link RequestResponse
     * @throws IOException Will be thrown if the request can't be executed
     */
    public static RequestResponse performRequest(RequestBuilder requestBuilder) throws IOException 
        URL newUrl = new URL(requestBuilder.getPath());

        HttpURLConnection connection = (HttpURLConnection) newUrl.openConnection();
        connection.setRequestMethod(requestBuilder.getMethod().getType());
        requestBuilder.getHeaders().forEach(connection::setRequestProperty);
        connection.setConnectTimeout(5000);
        connection.setReadTimeout(5000);
        connection.setDoOutput(true);

        DataOutputStream out = new DataOutputStream(connection.getOutputStream());
        out.writeBytes(getParametersString(requestBuilder.getParams()));

        int status = connection.getResponseCode();
        String result = IOUtils.toString(connection.getInputStream(), "UTF-8");
        String contentType = connection.getHeaderField("Content-Type");
        connection.getInputStream().close();
        connection.disconnect();
        return new RequestResponse(status, result, contentType);
    

    /**
     * Makes from a map a valid HTTP string
     * Example: "myField=Hey!&myPassword=abc"
     *
     * @param params The parameters
     * @return The formed String
     * @throws UnsupportedEncodingException Should never be thrown
     */
    private static String getParametersString(Map<String, String> params) throws UnsupportedEncodingException 
        StringBuilder builder = new StringBuilder();
        for (Map.Entry<String, String> entry : params.entrySet()) 
            builder.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
            builder.append("=");
            builder.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
            builder.append("&");
        
        String result = builder.toString();
        return result.length() > 0 ? result.substring(0, result.length() - 1) : result;
    

    /**
     * A simple builder class for @link #performRequest(RequestBuilder)
     */
    @Data
    public static class RequestBuilder 

        private final String path;
        private final HttpRequestMethod method;

        private final Map<String, String> params = new HashMap<>();
        private final Map<String, String> headers = new HashMap<>();

        public RequestBuilder addParam(@NonNull String name, @NonNull String value) 
            this.params.put(name, value);
            return this;
        

        public RequestBuilder addHeader(@NonNull String name, @NonNull String value) 
            this.headers.put(name, value);
            return this;
        
    

    /**
     * A simplified http response.
     * Including status, message and the returned content type
     */
    @Data
    @AllArgsConstructor
    public static class RequestResponse 

        private int status;
        private String resultMessage;
        private String contentType;
    


package community.opencode.minetools4j.util.http;

import lombok.Getter;

/**
 * Simple enum for @link HttpRequest.
 * It's a better way than just write manually the method name
 */
public enum HttpRequestMethod 
    POST("POST"),
    GET("GET"),
    PUT("PUT"),
    HEAD("HEAD"),
    OPTIONS("OPTIONS"),
    DELETE("DELETE"),
    TRACE("TRACE");

    @Getter
    private String type;

    HttpRequestMethod(String type) 
        this.type = type;
    

这是我发出http请求的方法:

HttpRequest.RequestResponse requestResponse = HttpRequest.performRequest(new HttpRequest.RequestBuilder(API_URI + "/ping/" + host + "/" + port, HttpRequestMethod.GET));

感谢您的关注。

真诚地, 斯凯莱格

对不起,我的英语不好。我希望你能理解我;)

【问题讨论】:

第一个代码块中有两个类。抱歉,这是我的第一个问题 :) 405 表示“方法不允许”。您的问题与 CORS 无关,它只影响来自浏览器的 AJAX 请求。服务器可能需要一个帖子,而不是一个获取。 【参考方案1】:

什么是 HTTP 代码 405

状态 405 表示您发送的请求不允许您使用的方法。

Source

如何解决

您需要检查 API 文档,看看您是否有以下错误之一:

缺少 Auth 标头 缺少内容 网址错误 方法错误

简化代码

使用 unirest 可以简化您的请求代码,并涵盖边缘情况

【讨论】:

【参考方案2】:

如果您遇到此类错误:

对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,Origin 'http://localhost:4200' 不允许访问。响应的 HTTP 状态代码为 405。

您必须创建一个 servlet 过滤器并在 doFilter 方法上添加以下代码。

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
        throws IOException, ServletException 
    HttpServletRequest request = (HttpServletRequest) servletRequest;

    HttpServletResponse resp = (HttpServletResponse) servletResponse;
    resp.addHeader("Access-Control-Allow-Origin", "*");
    resp.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE,HEAD");
    resp.addHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    resp.addHeader("Accept-Encoding", "multipart/form-data");

    if (request.getMethod().equals("OPTIONS")) 
        resp.setStatus(200);
        return;
    
    chain.doFilter(request, servletResponse);
  

【讨论】:

这在浏览器中是准确的,但在浏览器外部的客户端应用程序中,它可能指向使用了错误的方法

以上是关于在 http 请求中使用 CORS的主要内容,如果未能解决你的问题,请参考以下文章

使用 ajax 发出 http 请求以获得基本授权和 cors

AngularJS $http 对 Web 服务的请求需要 CORS

如何在 Angular 2 中发出启用 CORS 的 HTTP 请求?

如何使用“no-cors”将 JavaScript HTTP 发布请求代码更改为 C#?

http 请求被 Flutter Web 的 Cors 策略阻止

GWT HTTP 请求响应代码 0 与 CORS 工作