标签归档:http

php curl模拟post请求提交数据例子总结

导读

在php中要模拟post请求数据提交我们会使用到curl函数,下面我来给大家举几个curl模拟post请求提交数据例子,有需要的朋友可参考参考。
注意:curl函数在php中默认是不被支持的,如果需要使用curl函数我们需在改一改你的php.ini文件的设置,找到php_curl.dll去掉前面的”;”就行了

情景

  1. 简单post数据
<?php
$uri = "http://the_site_to_test/test.php";
// 参数数组
$data = array (
        'name' => 'youname' 
// 'password' => 'password'
);
 
$ch = curl_init ();
curl_setopt ( $ch, CURLOPT_URL, $uri );//地址
curl_setopt ( $ch, CURLOPT_POST, 1 );//请求方式为post
curl_setopt ( $ch, CURLOPT_HEADER, 0 );//不打印header信息
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );//返回结果转成字符串
curl_setopt ( $ch, CURLOPT_POSTFIELDS, $data );//post传输的数据。
$return = curl_exec ( $ch );
curl_close ( $ch );
 
print_r($return);

接受php页面远程服务器:

<?php
if(isset($_POST['name'])){
    if(!empty($_POST['name'])){
        echo '您好,',$_POST['name'].'!';
    }
}
?>

2.用CURL模拟POST请求抓取邮编与地址,需要cookie做身份认证。

完整代码:

<?php
$runtime = new runtime ();
$runtime->start ();
$cookie_jar = tempnam('/tmp','cookie');
$filename = $argv[1];
$start_num= $argv[2];
$end_num  = $argv[3];

for($i=$start_num; $i<$end_num; $i++){
    $zip = sprintf('6s',$i);
    $fields_post = array(
            'postcode' => $zip, 
            'queryKind' => 2, 
            'reqCode' => 'gotoSearch', 
            'search_button.x'=>37,
            'search_button.y'=>12);


    $fields_string = http_build_query ( $fields_post, '&' );
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "URL?reqCode=gotoSearch&queryKind=2&postcode=".$zip);
    curl_setopt($ch, CURLOPT_HEADER, true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 120 );
    curl_setopt($ch, CURLOPT_REFERER, $refer );//有些网站会检查refer来屏蔽到程序的请求。所有需要模拟一个合法的。
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers_login );
    curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_jar );
    curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_jar );
    curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); 
    curl_setopt($ch, CURLOPT_POST, 1); // 发送一个常规的Post请求 
    curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string );


    $data = curl_exec($ch);
    
    preg_match_all('/id="table1">[s]*?<tr>[s]*?<td class="maintext">[sS]*?</td>[s]*?</tr>/', $data, $matches);
    if (!$handle = fopen($filename, 'a+')) {
        echo "不能打开文件 $filename";
        echo "n";
        exit;
    }


    if (fwrite($handle, $matches[0][1]) === FALSE) {
        echo "不能写入到文件 $filename";
        echo "n";
        exit;
    }


    echo "成功地将 $somecontent 写入到文件$filename";
    echo "n";


    fclose($handle);
    curl_close($ch);
}




class runtime
{
    var $StartTime = 0;
    var $StopTime = 0;
    function get_microtime()
    {
        list($usec,$sec)=explode(' ',microtime());return((float)$usec+(float)$sec);
    }
    function start()
    {
        $this->StartTime=$this->get_microtime();
    }
    function stop(){
        $this->StopTime=$this->get_microtime();
    }
    function spent()
    {
        return ($this->StopTime-$this->StartTime);
    }
}




$runtime->stop ();


$con = 'Processed in'.$runtime->spent().'seconds';
echo 'Processed in'. $runtime->spent().'seconds';

3.模拟POST请求 提交数据或上传文件 .

代码如下

http://www.a.com/a.php 发送POST请求

function execUpload(){


$file = '/doucment/Readme.txt';
$ch = curl_init();
$post_data = array(
    'loginfield' => 'username',
    'username' => 'ybb',
    'password' => '123456',
'file' => '@d:usrwwwtranslatedocumentReadme.txt'
);
curl_setopt($ch, CURLOPT_HEADER, false);
//启用时会发送一个常规的POST请求,类型为:application/x-www-form-urlencoded,就像表单提交的一样。
curl_setopt($ch, CURLOPT_POST, true);  
curl_setopt($ch,CURLOPT_BINARYTRANSFER,true);
curl_setopt($ch, CURLOPT_POSTFIELDS,$post_data);
curl_setopt($ch, CURLOPT_URL, 'http://www.b.com/handleUpload.php');
$info= curl_exec($ch);
curl_close($ch);
   
print_r($info);

}

2.http://www.b.com/handleUpload.php

function handleUpload(){
    print_r($_POST);
    echo '===file upload info:';
    print_r($_FILES);
}

4. post json数据

$data = array("name" => "Hagrid", "age" => "36");
$data_string = json_encode($data);

$ch = curl_init('http://api.local/rest/users');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS,$data_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/json',
    'Content-Length: ' . strlen($data_string))
);
 
$result = curl_exec($ch);

 

■cURL 函数

■curl_close — 关闭一个cURL会话
■curl_copy_handle — 复制一个cURL句柄和它的所有选项
■curl_errno — 返回最后一次的错误号
■curl_error — 返回一个保护当前会话最近一次错误的字符串
■curl_exec — 执行一个cURL会话
■curl_getinfo — 获取一个cURL连接资源句柄的信息
■curl_init — 初始化一个cURL会话
■curl_multi_add_handle — 向curl批处理会话中添加单独的curl句柄
■curl_multi_close — 关闭一组cURL句柄
■curl_multi_exec — 运行当前 cURL 句柄的子连接
■curl_multi_getcontent — 如果设置了CURLOPT_RETURNTRANSFER,则返回获取的输出的文本流
■curl_multi_info_read — 获取当前解析的cURL的相关传输信息
■curl_multi_init — 返回一个新cURL批处理句柄
■curl_multi_remove_handle — 移除curl批处理句柄资源中的某个句柄资源
■curl_multi_select — 等待所有cURL批处理中的活动连接
■curl_setopt_array — 为cURL传输会话批量设置选项
■curl_setopt — 设置一个cURL传输选项
■curl_version — 获取cURL版本信息

总结

结合这篇和通过php写wordpress博客就可以抓取别人的文章 然后自动发博客。当然这里面其实还少了一讲,正则表达式。不过 可以用php-readability,git上就有源码。

mac上建议安装Dash,看各种文档很方便。

Anroid https代码示例

https与http的通信,在我看来主要的区别在于https多了一个安全验证机制,而Android采用的是X509验证,首先我们需要这重写X509类,建立我们的验证规则、、不过对于特定的项目,我们一般都是无条件信任服务端的,因此我们可以对任何证书都无条件信任(其实本质上我们只是信任了特定url的证书,为了偷懒,才那么选择的)/**

 * 信任所有主机-对于任何证书都不做检查
 */
class MytmArray implements X509TrustManager {
    public X509Certificate[] getAcceptedIssuers() {
        // return null;
        return new X509Certificate[] {};
    }
    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        // TODO Auto-generated method stub
    }
    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        // TODO Auto-generated method stub
        // System.out.println("cert: " + chain[0].toString() + ", authType: "
        // + authType);
    }
};

好了,我们写好了信任规则,接下载就要创建一个主机的信任列表

static TrustManager[] xtmArray = new MytmArray[] { new MytmArray() };
    /**
     * 信任所有主机-对于任何证书都不做检查
     */
    private static void trustAllHosts() {
        // Create a trust manager that does not validate certificate chains
        // Android 采用X509的证书信息机制
        // Install the all-trusting trust manager
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, xtmArray, new java.security.SecureRandom());
            HttpsURLConnection
                    .setDefaultSSLSocketFactory(sc.getSocketFactory());
            // HttpsURLConnection.setDefaultHostnameVerifier(DO_NOT_VERIFY);//
            // 不进行主机名确认
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            // TODO Auto-generated method stub
            // System.out.println("Warning: URL Host: " + hostname + " vs. "
            // + session.getPeerHost());
            return true;
        }
    };

上面的都是https通信需要做的几个基本要求,接下载我们要做的就是https的使用啦下面就以get和post为例进行说明,中间还涉及到cookie的使用

String httpUrl="XXXXX"
String result = "";
        HttpURLConnection http = null;
        URL url;
        try {
            url = new URL(httpUrl);
            // 判断是http请求还是https请求
            if (url.getProtocol().toLowerCase().equals("https")) {
                trustAllHosts();
                http = (HttpsURLConnection) url.openConnection();
                ((HttpsURLConnection) http).setHostnameVerifier(DO_NOT_VERIFY);// 不进行主机名确认
            } else {
                http = (HttpURLConnection) url.openConnection();
            }
            http.setConnectTimeout(10000);// 设置超时时间
            http.setReadTimeout(50000);
            http.setRequestMethod("GET");// 设置请求类型为
            http.setDoInput(true);
            http.setRequestProperty("Content-Type", "text/xml");
//http.getResponseCode());http或https返回状态200还是403
BufferedReader in = null;
            if (obj.getHttpStatus() == 200) {
                getCookie(http);
                in = new BufferedReader(new InputStreamReader(
                        http.getInputStream()));
            } else
                in = new BufferedReader(new InputStreamReader(
                        http.getErrorStream()));
            result = in.readLine();
            Log.i("result", result);
            in.close();
            http.disconnect();
 https或http的get请求写好了,哦中间涉及到了一个getCookie的方法,如下:
Java代码  收藏代码
/** 得到cookie */
    private static void getCookie(HttpURLConnection http) {
        String cookieVal = null;
        String key = null;
        DataDefine.mCookieStore = "";
        for (int i = 1; (key = http.getHeaderFieldKey(i)) != null; i++) {
            if (key.equalsIgnoreCase("set-cookie")) {
                cookieVal = http.getHeaderField(i);
                cookieVal = cookieVal.substring(0, cookieVal.indexOf(";"));
                DataDefine.mCookieStore = DataDefine.mCookieStore + cookieVal
                        + ";";
            }
        }
    }
public static Query HttpQueryReturnClass(String httpUrl, String base64) {

Java代码  收藏代码
        String result = "";
        Log.i("控制", httpUrl);
        Query obj = new Query();
        HttpURLConnection http = null;
        URL url;
        try {
            url = new URL(httpUrl);
            // 判断是http请求还是https请求
            if (url.getProtocol().toLowerCase().equals("https")) {
                trustAllHosts();
                http = (HttpsURLConnection) url.openConnection();
                ((HttpsURLConnection) http).setHostnameVerifier(DO_NOT_VERIFY);// 不进行主机名确认
            } else {
                http = (HttpURLConnection) url.openConnection();
            }
            http.setConnectTimeout(10000);// 设置超时时间
            http.setReadTimeout(50000);
            http.setRequestMethod("POST");// 设置请求类型为post
            http.setDoInput(true);
            http.setDoOutput(true);
            http.setRequestProperty("Content-Type", "text/xml");
            http.setRequestProperty("Cookie", DataDefine.mCookieStore);
            DataOutputStream out = new DataOutputStream(http.getOutputStream());
            out.writeBytes(base64);
            out.flush();
            out.close();
            obj.setHttpStatus(http.getResponseCode());// 设置http返回状态200还是403
            BufferedReader in = null;
            if (obj.getHttpStatus() == 200) {
                getCookie(http);
                in = new BufferedReader(new InputStreamReader(
                        http.getInputStream()));
            } else
                in = new BufferedReader(new InputStreamReader(
                        http.getErrorStream()));
            result = in.readLine();// 得到返回结果
            in.close();
            http.disconnect();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
}

这里面的base64是我经过base64加密过以后的数据

ios 访问http和https的代码示例

最近做个项目,开始采用的是HTTP协议实现客户端和服务器端的交互,后来需要改成HTTPS协议。在修改的过程中发现了一些问题,解决方案如下:

 

HTTP:

NSString *urlString =[NSString stringWithFormat:@”https://127.0.0.1/default.aspx?USER=%@”,@”111″];

 

NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];

[request setURL:[NSURL URLWithString:urlString]];

[request setHTTPMethod:@”GET”];

 

NSHTTPURLResponse* urlResponse = nil;

NSError *error = [[NSError alloc] init];

NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&error];

NSMutableString *result = [[NSMutableString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];

 

NSLog(@”The result string is :%@”,result);

 

HTTPS

事件触发

{

NSString *urlString =[NSString stringWithFormat:@”https://127.0.0.1/default.aspx?USER=%@”,@”111″];

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]        cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:5];

//设置请求方式为get

[request setHTTPMethod:@”GET”];

//添加用户会话id

[request addValue:@”text/html” forHTTPHeaderField:@”Content-Type”];

//连接发送请求

finished = false;

NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];

//堵塞线程,等待结束

while(!finished) {

[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];

}

}

 

– (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse*)response

{}

 

– (void)connectionDidFinishLoading:(NSURLConnection *)connection

{

//[_waitingDialog dismissWithClickedButtonIndex:0 animated:NO];

[connection release];

}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error

{

}

– (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection{

return NO;

}

//下面两段是重点,要服务器端单项HTTPS 验证,iOS 客户端忽略证书验证。

– (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {

return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];

}

– (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {

NSLog(@”didReceiveAuthenticationChallenge %@ %zd”, [[challenge protectionSpace] authenticationMethod], (ssize_t) [challenge previousFailureCount]);

 

if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]){

[[challenge sender]  useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];

[[challenge sender]  continueWithoutCredentialForAuthenticationChallenge: challenge];

}

}

NSLog(@”get the whole response”);

//[receivedData setLength:0];

}

//处理数据

– (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data

{

}

 

大家也可以参考下面一篇文章

关于在UIwebView中访问HTTPS站点的几种方法

 

使用Spring自定义注解生产Http接口描述信息

<

div id=”content” contentScore=”10814″>最近在做一个手机后台项目,使用的是SpringMVC,开发的接口是HTTP接口。在接口写完后需要在网页中吧接口的名称测试地址等信息添加到网页中,感觉这样很麻烦还容易漏。于是就写了一个自定义注解通过注解的方式将接口的描述信息加入到接口中,通过注解描述接口信息并且生产接口测试地址

先看使用方法及最终效果

 @ResponseBody
 @RequestMapping(“/getBusWaiting”)
 @AppInterface(value=”获取候车信息”,group=”test”,order=1,params={
   @InterfaceParam(name=”lineName”,desc=”线路名称”,testValue=”B2″),
   @InterfaceParam(name=”isUpDown”,desc=”上下行标识”,testValue=”1″),
   @InterfaceParam(name=”stationNum”,desc=”站序”,testValue=”0″),
   @InterfaceParam(name=”len”,desc=”长度”,testValue=”700″)
 })
 public AppResponse getBusWaitingInfo(String lineName,Integer isUpDown,Integer stationNum,Integer len){
  AppResponse result = new AppResponse();
  return result;
 }

生成的效果

使用Spring自定义注解生产Http接口描述信息

下面是具体实现

接口描述类

/** 
 *

创建人:王成委 

 *

创建时间:2014年12月8日 下午5:28:11 

 *

类描述: 标记手机App接口,接口描述信息,用于生成接口信息及测试路径

 *

版权说明: © 2014 Tiamaes

 */
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AppInterface {

 /**
  *

方法描述:接口名称

  * @return String
  */
 String value();
 
 /**
  *

方法描述:分组

  * @return String
  */
 String group() default “”;
 
 /**
  *

方法描述:排序

  * @return int
  */
 int order () default 0;
 
 /**
  *

方法描述:参数列表

  * @return InterfaceParam[]
  */
 InterfaceParam[] params() default {};
}

接口参数类

/** 
 *

创建人:王成委 

 *

创建时间:2014年12月8日 下午5:29:34 

 *

类描述: 手机App接口参数说明

 *

版权说明: © 2014 Tiamaes

 */
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InterfaceParam {
 
 /**
  *

方法描述:参数名称

  * @return String
  */
 String name();
 
 /**
  *

方法描述:接口说明

  * @return String
  */
 String desc();
 
 /**
  *

方法描述:测试参数值

  * @return String
  */
 String testValue() default “”;
}

testValue支持自定义变量,在主类中有具体实现

package com.tiamaes.gjds.app.aop;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.StringUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import com.tiamaes.gjds.app.annotation.AppInterface;
import com.tiamaes.gjds.app.annotation.InterfaceParam;
import com.tiamaes.gjds.app.base.RequestMethodMapping;
import com.tiamaes.gjds.app.base.RequestMethodParameter;
import com.tiamaes.gjds.app.base.Variable;
import com.tiamaes.gjds.util.SetUtils;

/** 
 *

类描述: 生成接口描述信息并放入Application中

 *

创建人:王成委 

 *

创建时间:2015年1月19日 下午4:42:24 

 *

版权说明: © 2015 Tiamaes

 * @see com.tiamaes.gjds.app.annotation.AppInterface
 */

public class InterfaceAnnotationConfigProcesser implements ApplicationContextAware,InitializingBean{

 private Log logger = LogFactory.getLog(getClass());
 
 private Map<String,List> mappers =
   new HashMap<String,List>();
 
 private WebApplicationContext applicationContext;
 
 /**
  *

方法描述:加载带有{@link com.tiamaes.gjds.app.annotation.AppInterface}注解的接口

  *

首先需要获取所有接口,然后过滤方法中带有@AppInterface

  *

创建人: 王成委 

  *

创建时间: 2015年1月10日 上午10:50:06

  */
 public void loadHandlerMapping(){
  this.logger.info(“初始化配置”);
  Map<String, HandlerMapping> handlers = BeanFactoryUtils.beansOfTypeIncludingAncestors(
    applicationContext, HandlerMapping.class, true, false);
 
  for(Entry<String, HandlerMapping> entry : handlers.entrySet()){
   HandlerMapping mapping = entry.getValue();
   if(mapping instanceof RequestMappingHandlerMapping){
    RequestMappingHandlerMapping requestHandler = (RequestMappingHandlerMapping)mapping;
    Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestHandler.getHandlerMethods();
    for(Entry<RequestMappingInfo, HandlerMethod> handlerMethod : handlerMethods.entrySet()){
     AppInterface annotation = handlerMethod.getValue().getMethodAnnotation(AppInterface.class);
     if(annotation== null)continue;
     PatternsRequestCondition patternsCondition = handlerMethod.getKey().getPatternsCondition();
     String requestUrl = SetUtils.first(patternsCondition.getPatterns());
     this.register(requestUrl, annotation,handlerMethod.getValue().getBeanType());
    }
   }
  }
 }
 
 /**
  *

方法描述:注册方法

  *

创建人: 王成委 

  *

创建时间: 2015年1月10日 上午10:50:06

  * @param requestUrl
  * @param annotation
  * @param beanType
  */
 private void register(String requestUrl, AppInterface annotation,
   Class<?> beanType) {
  String group = annotation.group();
  List groupMappers = this.mappers.get(group);
  if(groupMappers == null)groupMappers = new ArrayList();
  RequestMethodMapping mapper = new RequestMethodMapping();
  mapper.setGroup(group);
  mapper.setController(beanType.getName());
  mapper.setOrder(annotation.order());
  mapper.setName(annotation.value());
  mapper.setUrl(requestUrl);
  mapper.setParams(this.toParameters(annotation.params()));
  groupMappers.add(mapper);
  this.mappers.put(group, groupMappers);
 }
 
 /**
  *

方法描述:读取参数

  *

创建人: 王成委 

  *

创建时间: 2015年1月10日 上午10:50:06

  * @param params
  * @return
  */
 private List toParameters(InterfaceParam[] params){
  List parameters = new ArrayList();
 
  for(InterfaceParam param : params){
   RequestMethodParameter bean = new RequestMethodParameter();
   bean.setName(param.name());
   bean.setDesc(param.desc());
   if(StringUtils.startsWithIgnoreCase(param.testValue(), “#”)){
    String var = param.testValue();
    String value = getByVariable(var.substring(var.indexOf(“#”)+1));
    bean.setTestValue(value);
   }else{
    bean.setTestValue(param.testValue());
   }
   parameters.add(bean);
  }
  return parameters;
 }
 
 /**
  *

方法描述:获取变量的值

  *

创建人: 王成委 

  *

创建时间: 2015年1月10日 上午10:50:06

  * @param var
  * @return
  */
 private String getByVariable(String var){
  Variable variable = Variable.valueOf(var);
  return variable.getValue();
 }

 /**
  *

方法描述:对接口方法根据分组排序

  *

创建人: 王成委 

  *

创建时间: 2015年1月20日 下午16:00:06

  */
 private void orderMappers(){
  for(Entry<String,List> entry : this.mappers.entrySet() ){
   Collections.sort(entry.getValue(), new Comparator() {
     
    @Override
    public int compare(RequestMethodMapping o1, RequestMethodMapping o2) {
     Integer one = o1.getOrder();
     Integer two = o2.getOrder();
     if(one != null && two != null) return one.intValue()-two.intValue();
     return 0;
    }
   });
  }
 }

 @Override
 public void setApplicationContext(ApplicationContext applicationContext)
   throws BeansException {
  this.applicationContext = (WebApplicationContext)applicationContext;
 }

 @Override
 public void afterPropertiesSet() throws Exception {
  this.loadHandlerMapping();
  this.orderMappers();
  this.applicationContext.getServletContext().setAttribute(“api”, this.mappers);
 }
 
 /**
  *

方法描述:刷新接口信息

  *

创建人: 王成委 

  *

创建时间: 2015年1月10日 上午10:50:06

  * @throws Exception
  */
 public void refresh() throws Exception{
  this.mappers = new HashMap<String,List>();
  this.afterPropertiesSet();
 }
}

利用C标签生产接口描述信息

 

 

       

       

       

       

 
         

         

   

   
           
           

         

         

         

       
 
 

接口地址 接口名称 参数说明
     
   
           ${list.name}      
      ${params.name}:${params.desc}

     
     

Spring中如何配置Hibernate事务 http://www.linuxidc.com/Linux/2013-12/93681.htm

Struts2整合Spring方法及原理 http://www.linuxidc.com/Linux/2013-12/93692.htm

基于 Spring 设计并实现 RESTful Web Services http://www.linuxidc.com/Linux/2013-10/91974.htm

Spring-3.2.4 + Quartz-2.2.0集成实例 http://www.linuxidc.com/Linux/2013-10/91524.htm

使用 Spring 进行单元测试 http://www.linuxidc.com/Linux/2013-09/89913.htm

运用Spring注解实现Netty服务器端UDP应用程序 http://www.linuxidc.com/Linux/2013-09/89780.htm

Spring 3.x 企业应用开发实战 PDF完整高清扫描版+源代码 http://www.linuxidc.com/Linux/2013-10/91357.htm

Spring 的详细介绍请点这里
Spring 的下载地址请点这釼/div>

Spring Security 学习之HTTP表单验证

<

div id=”content” contentScore=”8510″>早已久仰Spring Security大名,一直没机会实践,最近计划对其进行系统学习并通过bolg将心得记录与博友们分享!

准备工作:
1. Spring Security 源码和Samples可以从以下链接下载:

https://github.com/spring-projects/spring-security/tree/master/samples
2. 从Spring官网下载STS
3. 学习时使用的版本 — Spring : 4.0.0.RELEASE,Spring Security : 3.2.0.RELEASE

历史:
前身为“The Acegi Security System for Spring”,始于2006年,项目得到广大认可和适用后更名为Spring Security纳入Spring的项目之一。

适用场景:
JAVA应用安全管理中的认证和授权,特别是使用Spring框架开发的JAVA应用。

基本原理:
Spring的DI和AOP — Spring Security大量使用AOP以避免对业务逻辑的干涉,并与Spring核心框架深度集成。
javax.servlet.FilterChain — 目前Spring Security主要用于web应用,在web应用中通过Filter拦截HTTP请求进行安检。

Spring Security 学习之HTTP表单验证

HTTP表单认证:
Spring Security 内置HTTP表单认证支持,使用Security名字空间可以非常简单让Web应用支持HTTP表单认证,基本使用步骤如下:
1. web.xml配置
首先我们需要在web描述符中配置一个Filter名为springSecurityFilterChain供Spring框架使用,这个名称不能自己随便更改,否则Spring框架会找不到。

  springSecurityFilterChain
  org.springframework.web.filter.DelegatingFilterProxy


  springSecurityFilterChain
  /*

  1. Spring bean配置
    Spring Security bean配置分两部分,分别是资源访问权限配置和用户定义,部分标签解说:
    http标签 :用于创建FilterChainProxy和它将使用的bean。
    auto-config=”true” :表示以下配置

           
       
     

intercept-url :定义被保护资源的访问权限
pattern :指定被保护的资源,可以使用正则表达式
access :访问权限定义,有多种方式,示例中使用角色,角色必须以ROLE_前缀开始。
user :定义用户名密码和拥有的角色,密码可以使用MD5加密。

    xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:security=”http://www.springframework.org/schema/security”
    xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd”>
   
                    access=”ROLE_ADMIN” />
       
   

   
       
           
                                    password=”stevex” />
                                    name=”admin” password=”admin” />
           

       

   

 

实践:
有很多安全相关的专业概念,需要自己慢慢认识,我们先创建一个实例,感性认识一下,步骤如下:
1. New–>Spring Project–>选择”Spring MVC Project”模板–Finish
2. 修改pom.xml,将Spring的版本更改为4.0.0.Release,增加Spring Security的依赖

org.springframework.security
    spring-security-core
    3.2.0.RELEASE


org.springframework.security
spring-security-config
3.2.0.RELEASE


org.springframework.security
spring-security-web
3.2.0.RELEASE

  1. 修改web.xml,增加springSecurityFilterChain

            contextConfigLocation        /WEB-INF/spring/root-context.xml /WEB-INF/spring/app-security.xml   

                                                                                         
       
                org.springframework.web.context.ContextLoaderListener       
        springSecurityFilterChain
       
        org.springframework.web.filter.DelegatingFilterProxy
       

       

       
        springSecurityFilterChain
        /*
       

  2. 增加app-security.xml

        xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:security=”http://www.springframework.org/schema/security”
        xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
            http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd”>
       
                        access=”ROLE_ADMIN” />
           
       

       
           
               
                                        password=”stevex” />
                                        name=”admin” password=”admin” />
               

           

       

  3. 修改HomeController.java,增加hello函数

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController {
                                               
    private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
                                               
    /**
    * Simply selects the home view to render by returning its name.
    */
    @RequestMapping(value = “/”, method = RequestMethod.GET)
    public String home(Locale locale, Model model) {
        logger.info(“Welcome home! The client locale is {}.”, locale);
                                                   
        Date date = new Date();
        DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
                                                   
        String formattedDate = dateFormat.format(date);
                                                   
        model.addAttribute(“serverTime”, formattedDate );
                                                   
        return “home”;
    }
                                               
    //produces=”text/plain” 必须有,否则会有乱码
    @RequestMapping(value = “/hello”, method = RequestMethod.GET, produces=”text/plain”)
    @ResponseBody
    public String hello(){
        logger.info(“request coming!”);
        return “Hello Stevex, you are so hard!”;
    }
                                               
}

  1. 运行应用进行测试

Spring Security 学习之HTTP表单验证

大功告成!

Spring Web MVC Security 下载地址

免费下载地址在 http://linux.linuxidc.com/

用户名与密码都是www.linuxidc.com

具体下载目录在 /2014年资料/2月/28旼/div>

Go 语言的 HTTP 标准库中的内存泄漏问题?

使用一个Go库实现的一个http服务器:

package main 

 

import ( 

    “net/http”

 

func main() { 

    http.ListenAndServe(“:8080”, nil) 

}

它将使用大约850kb的内存启动.通过你的浏览器向它发送一些请求. 你会观察到它(内存的使用)迅速上升到1mb. 如果你等着,你会发现它从来不会降下来. 现在(使用下面的脚本)用 Apache Bench 动一下它,你会发现内存使用仍然在增长. 一段时间过后它最终会维持在8.2mb左右.

Edit编辑: 看起来它并不会止步于8.2,而它的增长速度会显著减慢。现在它处在9.2的水平,并且仍然在增长.

总之,为什么会发生这样的事情呢?我使用了这段shell脚本一探究竟:

while [ true ] 

do

    ab -n 1000 -c 100 http://127.0.0.1:8080/ 

    sleep 1 

end

然后尝试获得这个的底线, 我已经尝试过调整设置. 试过使用r.Close = true 来阻止 Keep-Alive. 没有任何东西看起来是起作用的.

当我尝试去判断我正在编写的程序是否存在内存泄露时,我发现了这个问题的来由. 它有大量的http处理器和I/O调用. 检查过后我已经关闭了我所有的数据库链接,我继续观察,仍然会看到内存使用继续上升. 我的程序内存使用会维持在 433 MB 左右.

这里是 Goenv 的输出:

GOARCH=”amd64″

GOBIN=””

GOCHAR=”6″

GOEXE=””

GOHOSTARCH=”amd64″

GOHOSTOS=”darwin”

GOOS=”darwin”

GOPATH=”/Users/mark/Documents/Programming/Go”

GORACE=””

GOROOT=”/usr/local/go”

GOTOOLDIR=”/usr/local/go/pkg/tool/darwin_amd64″

TERM=”dumb”

CC=”clang”

GOGCCFLAGS=”-g -O2 -fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fno-common”

CXX=”clang++”

CGO_ENABLED=”1″

相关阅读:

Ubuntu 安装Go语言包 http://www.linuxidc.com/Linux/2013-05/85171.htm

《Go语言编程》高清完整版电子书 http://www.linuxidc.com/Linux/2013-05/84709.htm

Go语言并行之美 — 超越 “Hello World” http://www.linuxidc

CentOS 6.5 制作局域网http源

需要组件:虚拟机、CentOS-6.5-x86_64-minimal.iso 、CentOS-6.5-x86_64-bin-DVD1.iso。

1. 首先使用minimal安装虚拟机,实现最小化安装;

2. 接着进行一些基础配置;

2.1 虚拟机使用NAT 方式联网,同时找到网关的ip,此处是192.168.128.2 ,记录此网关ip;

2.2 配置静态ip以及机器名:

静态ip:(/etc/sysconfig/network-scripts/ifcfg-eth0)只用配置IPADDR、netmask、gateway、dns即可,修改ipv6init为no

DEVICE=”eth0″
BOOTPROTO=”static”
IPADDR=”192.168.128.100″
NETMASK=”255.255.255.0″
GATEWAY=”192.168.128.2″
DNS1=”8.8.8.8″
HWADDR=”00:0C:29:5E:9D:9E”
IPV6INIT=”no”

NM_CONTROLLED=”yes”
ONBOOT=”yes”
TYPE=”Ethernet”
UUID=”83afb8fd-3d1b-4ab5-bcd1-a1c4493d57b1″

机器名:(/etc/sysconfig/network),机器名设置为vm1

NETWORKING=yes
NETWORKING_IPV6=no
HOSTNAME=vm1
GATEWAY=192.168.128.2

配置ip映射:(/etc/hosts),vm2和vm3是属于一个集群,这样做为后面搭建Hadoop集群做准备。

192.168.128.100 vm1
192.168.128.101 vm2
192.168.128.102 vm3
127.0.0.1  vm1
::1        localhost localhost.localdomain localhost6 localhost6.localdomain6

重启虚拟机(如果只是修改了ip,那么不用重启亦可,但是此处我们修改了机器名,所以重启好点)。

3. 在终端中输入ping www.baidu.com测试是否含有网络连接,有则说明网络配置ok。

4. 配置本地源:

4.1 修改虚拟机中的iso文件为dvd版,如下图:

CentOS 6.5 制作局域网http源

4.2 挂载iso文件到/media/cdrom文件夹 : mkdir /media/cdrom  ;  mount /dev/cdrom /media/cdrom;

4.3 进入/etc/yum.repos.d文件夹可以看到:

CentOS-Debuginfo.repo CentOS-Vault.repo
CentOS-Base.repo  CentOS-Media.repo   

把 CentOS-D* 和CentOS-B* 重命名为后面都是加一个.bak 即可,修改CentOS-Media.repo文件:

[c6-media]
name=CentOS-$releasever – Media
baseurl=file:///media/cdrom/
gpgcheck=0
enabled=1

gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

运行 yum clean all , yum install vim ,如果vim 成功安装,那么就说明本地yum源配置成功。

5. 配置http源:

5.1 安装httpd :  yum install httpd;

5.2 关闭防火墙: service iptables stop ; chkconfig iptables off; setenforce 0 ;

修改/etc/selinux/config文件中的SELINUX=”” 为 disabled。
5.3 重新挂载iso到/media/cdrom,拷贝: cp -R /media/cdrom/Packages /var/www/html/rhel

5.4  安装createrepo, yum install createrepo*

5.5 生成repodata文件夹, createrepo /var/www/html/rhel ;

5.6 修改 /etc/httpd/conf/httpd.conf :  ServerAdmin  root@vm1  ServerName:vm1:80;

5.7 在/etc/yum.repo.d文件夹中添加一个 myiso.repo文件,内容如下:

[myiso]
name=myiso repo
baseurl=http://vm1/rhel
gpgcheck=0
enabled=1

gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

同时重命名CentOS-M* 为.bak;

5.8 启动httpd : httpd -k start  ; chkconfig httpd on

5.9  yum clean all ; yum install vim 如果提示已经安装过了,那就说明http局域网http源配置成功;

6 . 局域网内其他机器使用此http源:

在网络环境配置一致的情况下:

在/etc/yum.repo.d文件夹下面把之前新建的myiso.repo拷贝至此,同时重命名其他文件(后面加上.bak)即可。

使用 yum clean all ; yum install vim 进行测试。

更多CentOS相关信息见CentOS

HTTP协议初步解析

<

div id=”content” contentScore=”260″>一、什么是HTTP协议

HTTP是hypertext transfer protocol(超文本传输协议)的简写,它是TCP/IP协议的一个应用层协议,定义了Web客户端向Web服务器请求Web页面的方式,以及服务器向客户端传送Web页面的方式。

定义中的名词解释:
什么是超文本?
超文本是用超链接的方法,将各种不同空间的文字信息组织在一起的网状文本。
什么是应用层协议?
网络的设计者使用分层的方式组织网络协议以及实现这些协议的硬件和软件,历史上比较重要的一个协议组织模型是五层因特网协议栈,从顶层到底层,分别为应用层、运输层、网络层、链路层、物理层。其中应用层常见的协议有HTTP、SMTP、FTP等,运输层协议有TCP、UDP等,网络层有IP等。
 
二、HTTP协议特点
 
1. HTTP使用TCP作为它的运输层协议,TCP为HTTP提供可靠数据传输服务。使用了分层结构,HTTP协议不用担心数据丢失,也不用关注TCP从网络的数据丢失和乱序故障中恢复的细节。
2. HTTP是一个无状态协议,服务器向客户端发送被请求的文件,而不保存任何关于该客户的信息,(需要保存则应当使用cookie)。
3. HTTP/1.0使用非持续连接,HTTP/1.1使用持续连接。使用持续连接,在客户和服务器中不用多次分配TCP的缓冲区和保持TCP变量,同时避免了每一个传输对象的两倍RTT交付时延。HTTP的默认模式是使用带流水线的持续连接。
 
三、HTTP报文格式
 
1. 请求报文
 
举例如下:
GET  /somedir/page.html  HTTP/1.1
Host:  www.someschool.edu
Connection: close
User-agent: Mozilla/5.0
Accept-language: fr
——————————————————-
First line: request line
Other lines: header line
 
请求行: 方法字段 – URL字段 – HTTP版本字段
其中,方法字段可取GET, POST, HEAD, PUT, DELETE等
默认为GET请求,在URL后附带参数,有大小限制,不超过1K
表单提交中指明用POST时用POST,在实体中传递,无大小限制
HEAD方法常用于调试,只返回HTTP报文,不返回请求对象
Connection: close表示不使用持续连接
 
常见的请求头:
Accept: text/html,image/*   客户可接受的数据类型
Accept-Charset: ISO-8859-1  接受数据需要使用的字符集编码
Accept-Encoding: gzip,compress  接受的数据压缩格式
Accept-Language: en-us,zh-cn  接受的语言环境
Host: www.it315.org:80  虚拟主机名
If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT  缓存资源的最后获取时间
Referer: http://www.it315.org/index.jsp  当前的请求来自哪个链接
User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)  客户端的信息
Cookie 
Connection: close/Keep-Alive  指定是否保持连接
Date: Tue, 11 Jul 2000 18:23:51 GMT  当前时间
 
2. 响应报文
 
举例如下:
HTTP/1.1 200 ok
Connection: close
Date: Tue, 09 Aug 2011 15:44:04 GMT
Server: Apache/2.2.3 (CentOS)
Last-Modified: Tue, 09 Aug 2011 15:11:03 GMT
Content-Length: 6821
Content-Type: text/html
(Data, Data, Data …)
——————————————————-
First line: status line
Last line: entity body
Other lines: header line
 
状态行:协议版本 – 状态码 – 状态信息
状态码和状态信息常见的有:
200 OK
301 Moved Permanently
400 Bad Request
404 Not found
505 HTTP Version Not Supported
——————————————————-
100 ~ 199 表示成功接收,客户端需要继续提交才能完成整个过程,200 ~ 299 表示成功接收并已完成整个过程
300 ~ 399 为完成请求,客户需要进一步细化请求,如302请求重定向,304, 307 通知使用缓存
400 ~ 499 客户端请求有错误
500 ~ 599 服务器端出现错误
 
常见的响应头:

<

div>

Location: http://www.it315.org/index.jsp  配合302实现请求重定向
Server:apache tomcat  服务器的基本信息
Content-Encoding: gzip  服务器发送数据时使用的压缩格式
Content-Length: 80  发送数据的大小
Content-Language: zh-cn  发送数据使用的语言环境
Content-Type: text/html; charset=GB2312  当前所发送的数据的基本信息
Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT  缓存相关
Refresh: 1;url=http://www.it315.org  定时刷新到某个URL
Content-Disposition: attachment;filename=aaa.zip  与下载有关的头
Transfer-Encoding: chunked  数据传输类型,数据一块块传输
Set-Cookie:SS=Q0=5Lb_nQ; path=/search  设置cookie
ETag: W/”83794-1208174400000″  和缓存相关
Expires: -1 指定资源缓存的时间,如果取值为0或-1浏览就不缓存资源
Cache-Control: no-cache  如果为no-cache则通知浏览器不缓存
Pragma: no-cache   如果为no-cache则通知浏览器不缓存
由于历史原因,以上三个都用来控制缓存,同时使用
Connection: close/Keep-Alive  是否保持连接
Date: Tue, 11 Jul 2000 18:23:51 GMT 当前时间
 
 三、Telnet演示
telnet cis.poly.edu 80
 
 
<

如何配置使用 HTTP 严格传输安全(HSTS)

HTTP 严格传输安全(HSTS)是一种安全功能,web 服务器通过它来告诉浏览器仅用 HTTPS 来与之通讯,而不是使用 HTTP。本文会说明如何在 Apache2、Nginx 和 Lighttpd 上如何启用 HSTS。在主流的 web 服务器上测试通过: Nginx 1.1.19、 Lighttpd 1.4.28 和 Apache 2.2.22 ,环境为 Ubuntu 12.04、 Debian 6 & 7 和 CentOS 6,只需要调整部分参数就可以工作在其它的发行版上。

 

什么是 HTTP 严格传输安全?

引用自 Mozilla Developer Network

如果一个 web 服务器支持 HTTP 访问,并将其重定向到 HTTPS 访问的话,那么访问者在重定向前的初始会话是非加密的。举个例子,比如访问者输入 http://www.foo.com/ 或直接输入 foo.com 时。

这就给了中间人攻击的一个机会,重定向会可能会被破坏,从而定向到一个恶意站点而不是应该访问的加密页面。

HTTP 严格传输安全(HSTS)功能使 Web 服务器告知浏览器绝不使用 HTTP 访问,在浏览器端自动将所有到该站点的 HTTP 访问替换为 HTTPS 访问。

以下引自维基百科

HSTS 可以用来抵御 SSL 剥离攻击。SSL 剥离攻击是中间人攻击的一种,由 Moxie Marlinspike 于2009年发明。他在当年的黑帽大会上发表的题为 “New Tricks For Defeating SSL In Practice” 的演讲中将这种攻击方式公开。SSL剥离的实施方法是阻止浏览器与服务器创建HTTPS连接。它的前提是用户很少直接在地址栏输入https://,用户总是通过点击链接或3xx重定向,从HTTP页面进入HTTPS页面。所以攻击者可以在用户访问HTTP页面时替换所有https://开头的链接为http://,达到阻止HTTPS的目的。

HSTS可以很大程度上解决SSL剥离攻击,因为只要浏览器曾经与服务器创建过一次安全连接,之后浏览器会强制使用HTTPS,即使链接被换成了HTTP。

另外,如果中间人使用自己的自签名证书来进行攻击,浏览器会给出警告,但是许多用户会忽略警告。HSTS解决了这一问题,一旦服务器发送了HSTS字段,用户将不再允许忽略警告。

场景举例:

当你通过一个无线路由器的免费 WiFi 访问你的网银时,很不幸的,这个免费 WiFi 也许就是由黑客的笔记本所提供的,他们会劫持你的原始请求,并将其重定向到克隆的网银站点,然后,你的所有的隐私数据都曝光在黑客眼下。

严格传输安全可以解决这个问题。如果你之前使用 HTTPS 访问过你的网银,而且网银的站点支持 HSTS,那么你的浏览器就知道应该只使用 HTTPS,无论你是否输入了 HTTPS。这样就防范了中间人劫持攻击。

注意,如果你之前没有使用 HTTPS 访问过该站点,那么 HSTS 是不奏效的。网站需要通过 HTTPS 协议告诉你的浏览器它支持 HSTS。

服务器开启 HSTS 的方法是,当客户端通过HTTPS发出请求时,在服务器返回的 HTTP 响应头中包含 Strict-Transport-Security 字段。非加密传输时设置的HSTS字段无效。

 

在 Apache2 中设置 HSTS

编辑你的 apache 配置文件(如 /etc/apache2/sites-enabled/website.conf 和 /etc/apache2/httpd.conf ),并加以下行到你的 HTTPS VirtualHost:

  1. # Optionally load the headers module:
  2. LoadModule headers_module modules/mod_headers.so
  3. <VirtualHost67.89.123.45:443>
  4. Header always setStrict-Transport-Security"max-age=63072000; includeSubdomains; preload"
  5. VirtualHost>

现在你的 web 站点在每次访问时都会发送该请求头,失效时间是两年(秒数)。这个失效时间每次都会设置为两年后,所以,明天你访问时,它会设置为明天的两年后。

你只能在 HTTPS 虚拟机中设置这个头,而不能设置在 HTTP 虚拟机中。

要将你的访问者重定向到对应 HTTPS 站点,可使用如下设置:

  1. *:80>
  2. [...]
  3. ServerName example.com
  4. Redirect permanent / https://example.com/

如果仅仅是做重定向的话,甚至不需要设置 DocumentRoot。

你也可以使用 mod_rewrite 来做重定向,但是上述的方式更简单更安全。不过,mod_rewrite 可以重定向页面到对应的 HTTPS 页面,而上述配置则只重定向到“/”:

  1. *:80>
  2. [...]
  3. mod_rewrite.c>
  4. RewriteEngine On
  5. RewriteCond %{HTTPS} off
  6. RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

不要忘记重启 Apache。

 

Lighttpd

对于 lighttpd 来说很简单,将下述配置增加到你的 Lighttpd 配置文件(例如:/etc/lighttpd/lighttpd.conf):

  1. server.modules +=("mod_setenv")
  2. $HTTP["scheme"]=="https"{
  3. setenv.add-response-header =("Strict-Transport-Security"=>"max-age=63072000; includeSubdomains; preload")
  4. }

重启 Lighttpd。失效时间也是两年。

 

Nginx

Nginx 甚至更简单,将下述行添加到你的 HTTPS 配置的 server 块中:

  1. add_header Strict-Transport-Security"max-age=63072000; includeSubdomains; preload";

不要忘记重启 Nginx。